问题
I have a many-to-many association in EF Code-First (as explained in this question), and I want to use a one-to-many to the same entity as well. The problem is EF does not produce the right database scheme. Code:
public class A
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<B> ObjectsOfB { get; set; }
}
public class B
{
public int Id { get; set; }
public virtual A ObjectA { get; set; }
public virtual ICollection<A> OtherObjectsOfA { get; set; }
}
When I remove the ObjectA property of class B the many-to-many association is generated correctly. When generated incorrectly, entity B gets 2 foreign keys to A, and entity A gets 1 foreign key to B (like a many-to-one relation).
回答1:
If you have more than one navigation property refering to the same entity EF does not know where the inverse navigation property on the other entity belongs to. In your example: Does A.ObjectsOfB
refer to B.ObjectA
or to B.OtherObjectsOfA
? Both would be possible and a valid model.
Now, EF does not throw an exception like "cannot determine relationships unambiguously" or something. Instead it decides that B.ObjectA
refers to a third endpoint in B
which is not exposed as navigation property in the model. This creates the first foreign key in table B
. The two navigation properties in B
refer to two endpoints in A
which are also not exposed in the model: B.ObjectA
creats the second foreign key in table B
and B.OtherObjectsOfA
creates a foreign key in table A
.
To fix this you must specify the relationships explicitely.
Option one (the easiest way) is to use the InverseProperty
attribute:
public class A
{
public int Id { get; set; }
public string Name { get; set; }
[InverseProperty("OtherObjectsOfA")]
public virtual ICollection<B> ObjectsOfB { get; set; }
}
This defines that A.ObjectsOfB
is part of a many-to-many relation to B.OtherObjectsOfA
.
The other option is to define the relationships completely in Fluent API:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<A>()
.HasMany(a => a.ObjectsOfB)
.WithMany(b => b.OtherObjectsOfA)
.Map(x =>
{
x.MapLeftKey("AId");
x.MapRightKey("BId");
x.ToTable("ABs");
});
modelBuilder.Entity<B>()
.HasRequired(b => b.ObjectA) // or HasOptional
.WithMany()
.WillCascadeOnDelete(false); // not sure if necessary, you can try it
// without if you want cascading delete
}
回答2:
If table B has foreign key to table A then class B has navigation property to A and A have navigation property to ICollection<A>
.
If table B has many to many relation with table A then class A must have ICollection<B>
and class B must have ICollection<A>
.
Try that, maybe this will clarify your request from the EF.
来源:https://stackoverflow.com/questions/8228948/using-both-many-to-many-and-one-to-many-to-same-entity