实体框架代码优先,同一张表上的多对多关系
Posted
技术标签:
【中文标题】实体框架代码优先,同一张表上的多对多关系【英文标题】:Entity Framework code-first, Many-to-Many relationship on the same table 【发布时间】:2016-10-10 16:25:11 【问题描述】:我正在建立一个具有好友功能的社交网络。 我的想法是我已经有了默认的 ApplicationUser 类,所以我创建了一个名为 Friend
的新表public class Friend
[Key]
[Column(Order = 1)]
public string SenderId get; set;
[Key]
[Column(Order = 2)]
public string ReceiverId get; set;
//Status == true : Friend request accepted
//Status == false : Friend request not accepted
public bool Status get; set;
在 ApplicationUser 中,我定义了 2 个导航属性 Senders 和 Receivers(链接到 Friend 表)
public class ApplicationUser : IdentityUser
[Required]
[StringLength(50)]
public string Name get; set;
[Required]
public bool Gender get; set;
[StringLength(255)]
public string Address get; set;
[StringLength(255)]
public string Job get; set;
[StringLength(255)]
public string Image get; set;
public DateTime Birthday get; set;
public ICollection<ApplicationUser> Senders get; set;
public ICollection<ApplicationUser> Receivers get; set;
最后在 ApplicationDbContext 中,我使用 Fluent Api 声明了 2 个表之间的关系
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
public DbSet<Friend> Friends get; set;
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
public static ApplicationDbContext Create()
return new ApplicationDbContext();
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity<ApplicationUser>()
.HasMany(a => a.Senders)
.WithMany(a => a.Receivers)
.Map(m =>
m.MapLeftKey("ReceiverId");
m.MapRightKey("SenderId");
m.ToTable("Friends");
);
base.OnModelCreating(modelBuilder);
但是当我添加迁移时,它会创建 2 个这样的表,它们都不是我需要的(一个没有外键,一个没有 Status 属性)
public override void Up()
CreateTable(
"dbo.Friends1",
c => new
SenderId = c.String(nullable: false, maxLength: 128),
ReceiverId = c.String(nullable: false, maxLength: 128),
Status = c.Boolean(nullable: false),
)
.PrimaryKey(t => new t.SenderId, t.ReceiverId );
CreateTable(
"dbo.Friends",
c => new
SenderId = c.String(nullable: false, maxLength: 128),
ReceiverId = c.String(nullable: false, maxLength: 128),
)
.PrimaryKey(t => new t.SenderId, t.ReceiverId )
.ForeignKey("dbo.AspNetUsers", t => t.SenderId)
.ForeignKey("dbo.AspNetUsers", t => t.ReceiverId)
.Index(t => t.SenderId)
.Index(t => t.ReceiverId);
我该怎么办:(我在网上搜索过,这似乎是合法的,但它不起作用
【问题讨论】:
【参考方案1】:但是当我添加迁移时,它会创建 2 个这样的表,它们都不是我需要的(一个没有外键,一个没有 Status 属性)
这是因为您混合了 EF 支持的两种可能的 many-to-many
关联 - 一种使用隐式联结表(来自 Fluent API 配置),另一种使用显式联结表(Friend
实体)和两个 one-to-many
关联.
由于只有在您没有与关联关联的其他数据并且您有一个(Status
属性)时才能使用第一种方法,因此您需要使用第二种方法。
为此,请按如下方式更改导航属性的类型:
public class ApplicationUser : IdentityUser
// ...
public ICollection<Friend> Senders get; set;
public ICollection<Friend> Receivers get; set;
和配置:
modelBuilder.Entity<ApplicationUser>()
.HasMany(e => e.Senders)
.WithRequired()
.HasForeignKey(e => e.ReceiverId);
modelBuilder.Entity<ApplicationUser>()
.HasMany(e => e.Receivers)
.WithRequired()
.HasForeignKey(e => e.SenderId);
【讨论】:
还有一个问题,如何获取一个用户的好友列表? 我需要一个 ApplicationUser 列表,它们是另一个 ApplicationUser 的朋友。所以我传入它的 ID 和查询如下 var friends = (from f in _context.Friends from u in _context.Users where f.ReceiverId == u.Id || f.SenderId == u.Id where u.Id==id其中 f.Status==true 选择新 Id=u.Id, Name=u.Name, ).ToList();var friends = (from u in _context.Users where u.Id == id from fId in (from s in u.Senders where s.Status == true select s.SenderId) .Concat(from r in u.Receivers where r.Status == true select r.ReceiverId) join f in _context.Users on fId equals f.Id select new Id = f.Id, Name = f.Name, ) .ToList();
谢谢,但似乎查询实际上让用户获得了自己而不是朋友以上是关于实体框架代码优先,同一张表上的多对多关系的主要内容,如果未能解决你的问题,请参考以下文章