The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations

lintmouse picture lintmouse · Jun 22, 2013 · Viewed 40.5k times · Source

"The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations."

I am getting this error in Entity Framework 4.4 when updating/migrating the database, but I am not trying to specify a 1:1 relationship. I want something like this:

public class EntityA
{
    public int ID { get; set; }
    public int EntityBID { get; set; }

    [ForeignKey("EntityBID")]
    public virtual EntityB EntityB { get; set; }
}

public class EntityB
{
    public int ID { get; set; }
    public Nullable<int> PreferredEntityAID { get; set; }

    [ForeignKey("PreferredEntityAID")]
    public virtual EntityA PreferredEntityA { get; set; }
}

where EntityA must have an EntityB parent, whereas EntityB can have a preferred EntityA child, but doesn't have to. The preferred child should be one of the children associated with the parent, but I don't know how to enforce this in the database. I'm planning on enforcing it programmatically.

How do I get around this error or what is a better way of accomplishing these relationships?

Answer

Slauma picture Slauma · Jun 23, 2013

Entity Framework Code-First conventions are assuming that EntityA.EntityB and EntityB.PreferredEntityA belong to the same relationship and are the inverse navigation properties of each other. Because both navigation properties are references (not collections) EF infers a one-to-one relationship.

Since you actually want two one-to-many relationships you must override the conventions. With your model it's only possible with Fluent API:

modelBuilder.Entity<EntityA>()
    .HasRequired(a => a.EntityB)
    .WithMany()
    .HasForeignKey(a => a.EntityBID);

modelBuilder.Entity<EntityB>()
    .HasOptional(b => b.PreferredEntityA)
    .WithMany()
    .HasForeignKey(b => b.PreferredEntityAID);

(If you use this you can remove the [ForeignKey] attributes.)

You cannot specify a mapping that would ensure that the preferred child is always one of the associated childs.

If you don't want to use Fluent API but only data annotations you can add a collection property in EntityB and relate it to EntityA.EntityB using the [InverseProperty] attribute:

public class EntityB
{
    public int ID { get; set; }
    public Nullable<int> PreferredEntityAID { get; set; }

    [ForeignKey("PreferredEntityAID")]
    public virtual EntityA PreferredEntityA { get; set; }

    [InverseProperty("EntityB")] // <- Navigation property name in EntityA
    public virtual ICollection<EntityA> EntityAs { get; set; }
}