2

I have the following classes (shortened for brevity);

public class InsurancePolicy : AuditableEntity<int>
{
    [Column("id"), Key]
    public override int ID { get; set; }
    [Column("deviceid"), ForeignKey("Device")]
    public int DeviceId { get; set; }
    public virtual Device Device { get; set; }
}

public partial class Device : AuditableEntity<int>
{
    [Column("deviceid"), Key]
    public override int ID { get; set; }

    [ForeignKey("Policy")]
    public int PolicyId { get; set; }
    public virtual InsurancePolicy Policy { get; set; }

    [ForeignKey("Vehicle")]
    public int VehicleId { get; set; }
    public virtual Vehicle Vehicle { get; set; }
}

public partial class Vehicle : AuditableEntity<int>
{
    [Column("id"), Key]
    public override int ID { get; set; }

    [Column("deviceid"), ForeignKey("Device")]
    public int DeviceId { get; set; }
    public virtual Device Device { get; set; }

    public virtual List<InsurancePolicyVehicle> InsurancePolicyVehicles { get; set; }
}

Now when I try and run my update-database command I get this error:

Device_Policy_Target: : Multiplicity is not valid in Role 'Device_Policy_Target' in relationship 'Device_Policy'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.

Device_Vehicle_Target: : Multiplicity is not valid in Role 'Device_Vehicle_Target' in relationship 'Device_Vehicle'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.

Could anyone please advise what I am doing wrong here?

1
  • I feel cross relation between classes. 'InsurancePolicy ' class referring 'Device' class at same time, it referring back too. I think this is not acceptable. Kindly optimize table relationship Commented Sep 1, 2015 at 12:21

1 Answer 1

1

Taking the Device_Policy_Target relationship as an example, you have the following (trimming down to the the relevant properties for this relationship):

public class InsurancePolicy : AuditableEntity<int>
{   
    [Column("id"), Key]
    public override int ID { get; set; }
    [Column("deviceid"), ForeignKey("Device")]
    public int DeviceId { get; set; }
    public virtual Device Device { get; set; }
}

public partial class Device : AuditableEntity<int>
{
    [Column("deviceid"), Key]
    public override int ID { get; set; }

    [ForeignKey("Policy")]
    public int PolicyId { get; set; }
    public virtual InsurancePolicy Policy { get; set; }

}

What you're defining here is a one-to-one relationship. EF only supports such relationships where the two tables share the primary key. In your configuration your child table - InsurancePolicy has its own PK, and a Foreign Key to Device. EF only supports one-to-many relationships with these constraints.

To define these relationships to be one-to-one, switch your setup to something along the lines of:

public class InsurancePolicy : AuditableEntity<int>
{
    [Column("deviceid"), Key, ForeignKey("Device")]
    public override int ID { get; set; }
    public virtual Device Device { get; set; }
}

public partial class Device : AuditableEntity<int>
{
    [Column("deviceid"), Key]
    public override int ID { get; set; }

    public virtual InsurancePolicy Policy { get; set; }    
}

This is all partially a consequence of EF not supporting unique constraints. This article has a fuller explanation of one-to-one relationships using DataAnnotations

Update:

To "fake" the one-to-one using the tables/keys you've got then consider something like this:

public class InsurancePolicy : AuditableEntity<int>
{   
    [Column("id"), Key]
    public override int ID { get; set; }
    [Column("deviceid"), ForeignKey("Device")]
    public int DeviceId { get; set; }
    public virtual Device Device { get; set; }
}

public partial class Device : AuditableEntity<int>
{
    [Column("deviceid"), Key]
    public override int ID { get; set; }

    public virtual IEnumerable<InsurancePolicy> PoliciesAsList { get; set; }

    [NotMapped]
    public virtual InsurancePolicy Policy {
        get {
            return (PoliciesAsList != null) 
                ? PoliciesAsList.FirstOrDefault() 
                : null;                
        }
    }

}

In this case I've arbitrarly chosen Device as the parent - it's not important which you choose.

You should also make sure that the database has a unique constraint on deviceid on the InsurancePolicy table.

Sign up to request clarification or add additional context in comments.

7 Comments

Hi Jon, Thanks for the reply. The only issue I have here is that the tables are existing in the database (i.e. deviceid is the PK in devices and id is the PK in InsurancePolicy). So I would need to keep for example [Column("id"), Key] public override int ID { get; set; } as the PK is id effectively in the db and the dba will not allow it to be changed. Any suggestion under this situation?
Hi Jon, Many thanks for taking the time to look at this. I need to adjust and make some changes to the tables, but I have been told that existing column names must remain. So in this case a device can live independently of a policy and vice versa. They can and will be linked eventually (i.e. once they are allocated etc).
You'll have to switch them to be one-to-many relationships in EF then - for the configuration at least. You can always add an additional property retrieve the first item in the list if it exists, and null otherwise.
just to add so what i am trying to achieve is simply have a deviceid column in insurance policy (which can be null) and a policyid column in the device table, again which can be null. Then when the device is allocated tot he policy this would simply be filled in. For ease of use in the EF I would like to be able to access form either side (i.e. get the policy from the dvice and vice versa). Is this possible?
Choose one to be nominally be the parent - you don't need Ids on both side to make the link.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.