Entity Framework 多对多相同 table
Entity Framework many to many on same table
我正在使用 C# 和 Entity Framework,代码优先迁移。
我有一个class,user
,它与自身有多对多关系,与属性 Friends
。目前我有这段代码负责创建数据库结构和关系本身。
[InverseProperty("ReverseFriends")]
public virtual ICollection<User> Friends { get; set; }
[InverseProperty("Friends")]
public virtual ICollection<User> ReverseFriends { get; set; }
但是我 suspect/hope 有一种方法可以只用一个导航 属性,而不是两个。是这样吗?或者我这样做的方式是在单个 table 上做多对多的方式吗?
你的模型和数据注释都很好。
However I suspect/hope there is a way to do this with only a single navigation property, instead of two.
否定。关系总是包括两个 实体(尽管它们可以是一个并且与这里的类型相同)。多对多 w/o 流畅 API 需要 两个 导航属性。
想象一下两个实体 A
和 B
之间的多对多关系:
public class A
{
[InverseProperty("As")]
public ICollection<B> Bs { get; set; }
}
public class B
{
[InverseProperty("Bs")]
public ICollection<A> As { get; set; }
}
请注意,在这种情况下,InverseProperty
注释是可选的,因为 EF 可以自动关联两个导航属性并形成单一的多对多关系。
现在替换A == B
。我们得到的是:
public partial class A
{
[InverseProperty("As")]
public ICollection<A> Bs { get; set; }
}
public partial class A
{
[InverseProperty("Bs")]
public ICollection<A> As { get; set; }
}
或合并后:
public class A
{
[InverseProperty("As")]
public ICollection<A> Bs { get; set; }
[InverseProperty("Bs")]
public ICollection<A> As { get; set; }
}
即正是你所做的。
如果您只想通过一个导航创建关系 属性,那么您必须使用流畅 API。例如,如果您只想保留 Friends
,例如
public class User
{
// ...
public virtual ICollection<User> Friends { get; set; }
}
您需要以下流畅的配置:
modelBuilder.Entity<User>()
.HasMany(u => u.Friends)
.WithMany(); // no inverse navigation property
但请注意,虽然这允许您定义关系,但 Friends
属性 仍将仅包含连接 table 中的元素,假设 UserId
等于 User.Id
。它不会包含连接 table 的元素,其中 FriendId
等于 User.Id
.
最好是保留两个导航属性并显式配置连接 table,例如
public class User
{
// ...
public virtual ICollection<User> Friends { get; set; }
public virtual ICollection<User> FriendOf { get; set; }
}
modelBuilder.Entity<User>()
.HasMany(u => u.Friends)
.WithMany(u => u.FriendOf);
.Map(m => m.ToTable("UserFriends")
.MapLeftKey("UserId")
.MapRightKey("FriendId"));
这允许您获取用户为 UserId
或 FriendId
的所有加入 table 元素,即所有用户好友:
var query = db.Users.Select(u => new
{
User = u,
AllFriends = u.Friends.Concat(u.FriendOf).ToList(),
});
我正在使用 C# 和 Entity Framework,代码优先迁移。
我有一个class,user
,它与自身有多对多关系,与属性 Friends
。目前我有这段代码负责创建数据库结构和关系本身。
[InverseProperty("ReverseFriends")]
public virtual ICollection<User> Friends { get; set; }
[InverseProperty("Friends")]
public virtual ICollection<User> ReverseFriends { get; set; }
但是我 suspect/hope 有一种方法可以只用一个导航 属性,而不是两个。是这样吗?或者我这样做的方式是在单个 table 上做多对多的方式吗?
你的模型和数据注释都很好。
However I suspect/hope there is a way to do this with only a single navigation property, instead of two.
否定。关系总是包括两个 实体(尽管它们可以是一个并且与这里的类型相同)。多对多 w/o 流畅 API 需要 两个 导航属性。
想象一下两个实体 A
和 B
之间的多对多关系:
public class A
{
[InverseProperty("As")]
public ICollection<B> Bs { get; set; }
}
public class B
{
[InverseProperty("Bs")]
public ICollection<A> As { get; set; }
}
请注意,在这种情况下,InverseProperty
注释是可选的,因为 EF 可以自动关联两个导航属性并形成单一的多对多关系。
现在替换A == B
。我们得到的是:
public partial class A
{
[InverseProperty("As")]
public ICollection<A> Bs { get; set; }
}
public partial class A
{
[InverseProperty("Bs")]
public ICollection<A> As { get; set; }
}
或合并后:
public class A
{
[InverseProperty("As")]
public ICollection<A> Bs { get; set; }
[InverseProperty("Bs")]
public ICollection<A> As { get; set; }
}
即正是你所做的。
如果您只想通过一个导航创建关系 属性,那么您必须使用流畅 API。例如,如果您只想保留 Friends
,例如
public class User
{
// ...
public virtual ICollection<User> Friends { get; set; }
}
您需要以下流畅的配置:
modelBuilder.Entity<User>()
.HasMany(u => u.Friends)
.WithMany(); // no inverse navigation property
但请注意,虽然这允许您定义关系,但 Friends
属性 仍将仅包含连接 table 中的元素,假设 UserId
等于 User.Id
。它不会包含连接 table 的元素,其中 FriendId
等于 User.Id
.
最好是保留两个导航属性并显式配置连接 table,例如
public class User
{
// ...
public virtual ICollection<User> Friends { get; set; }
public virtual ICollection<User> FriendOf { get; set; }
}
modelBuilder.Entity<User>()
.HasMany(u => u.Friends)
.WithMany(u => u.FriendOf);
.Map(m => m.ToTable("UserFriends")
.MapLeftKey("UserId")
.MapRightKey("FriendId"));
这允许您获取用户为 UserId
或 FriendId
的所有加入 table 元素,即所有用户好友:
var query = db.Users.Select(u => new
{
User = u,
AllFriends = u.Friends.Concat(u.FriendOf).ToList(),
});