如何在实体框架中读取和写入多对多关联

本文关键字:关联 读取 实体 框架 | 更新日期: 2023-09-27 18:30:17

这似乎应该很简单,但多年来我一直无法找到清晰/好的解决方案。

很简单,我正在使用实体框架构建一个聊天程序来存储我的用户数据。

我有一个名为User的类。用户有一个朋友(其他用户)列表,如下所示

public class User
{
    [Key]
    public int ID { get; set; }   
    //whole bunch of other properties like 'username' etc.
    public List<User> Friends { get; set; }
    public User()
    {
        this.Friends = new List<User>();
    }
}

EF 非常高兴地创建了我的用户表,但我一生都无法弄清楚如何编写/读取用户列表。

在寻找答案时,我确实发现了一件事:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().
            HasMany(m => m.Friends).
            WithMany()
            .Map(m =>
            {
                m.ToTable("UsersFriends");
                m.MapLeftKey("UserId");
                m.MapRightKey("FriendId");
            });
}

这为我创建了一个很好的表格,其中包含用户的 ID 和用户朋友的 ID,但不知道如何将列表添加到此表。我猜是因为新列表()与DBContext无关。

如何在实体框架中读取和写入多对多关联

你应该把你的朋友列表virtual

public virtual ICollection<User> Friends { get; set; }

我不太确定是否需要使用 ICollection<T> 而不是 List<T>,但这是我在大多数 EF 示例中看到的,也是我自己多年来一直在使用的。

要添加好友,您可以执行以下操作:

var john = new User { Username = "John" };
var bob = new User { Username = "Bob" };
john.Friends.Add(bob);
context.Users.Add(john);
context.Users.Add(bob);
context.SaveChanges();

要获取用户的好友列表,您可以执行以下操作:

// Eager load the friends
var userWithFriends = context.Users.Include(x => x.Friends).SingleOrDefault(x => x.Username == "john");
// Lazy loading
var user = context.Users.SingleOrDefault(x => x.Username == "John");
var friends = user.Friends.ToList();

更新

向现有用户添加新好友

var dave = new User { Username = "Dave" };
var john = context.Users.Single(x => x.Username == "John");
john.Friends.Add(dave);
context.SaveChanges();
将现有用户

作为好友添加到现有用户

var john = context.Users.Single(x => x.Username == "John");
var walter = context.Users.Single(x => x.Username == "Walter");
john.Friends.Add(walter);
context.SaveChanges();
// OR
var bob = new User { UserId = 2 };
var walter = new User { UserId = 4 };
context.Users.Attach(bob);
context.Users.Attach(walter);
bob.Friends.Add(walter);
context.SaveChanges();

移除好友

var john = context.Users.Single(x => x.Username == "John");
var bob = context.Users.Single(x => x.Username == "Bob");
john.Friends.Remove(bob);
context.SaveChanges();
// OR
var john = context.Users.Single(x => x.Username == "John");
var walter = new User { UserId = 4 };
context.Users.Attach(walter);
john.Friends.Remove(walter);
context.SaveChanges();

感谢克里斯托夫和其他人,我设法解决了我的问题,并实现了创建/保存/更新list<t>到我的数据库的能力。这是我所做的:

用户类:

public class User
{
    [Key]
    public int ID { get; set; }   
    //whole bunch of other properties like 'username' etc.
    //I have switched back to List<T> after using IEnumerable because despite what I keep reading
    //you can use them, and I ran into problems using .ToList() where the results were empty.
    public List<User> Friends { get; set; }
    public User()
    {
        //Removed this line because the instance is created when we get the user using DbContext 
        //this.Friends = new List<User>();
    }
}

创建关系表:

这将创建存储"朋友"列表内容的关系表。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
     modelBuilder.Entity<User>().
         HasMany(m => m.Friends).
         WithMany()
         .Map(m =>
         {
             m.ToTable("UsersFriends");
             m.MapLeftKey("UserId");
             m.MapRightKey("FriendId");
         });
}

从数据库获取列表

public static User GetUser(string Username)
{
    using (Context DB = new Context())
    {               
        //This creates the instance of List<User> and gets the data (again, thanks Kristof!)
        return DB.Users.Include(x => x.Friends).SingleOrDefault(x => x.Username == Username);                   
    }
}

将列表保存/更新到数据库

以前版本的代码使用 DB.Entry(user).State = EntityState.Modified; DB.SaveChanges(); 可以很好地更新用户属性,但"朋友"列表被忽略,关系表没有更新,或者关系表已更新,但我最终在我的用户表中有重复的条目。这是因为用户实体在尝试更新时处于脱机状态。

解决此问题的解决方法是使用 GraphDiff 包,该包将扩展方法添加到 EF 以更新脱机实体。代码如下:

public static void UpdateUser(User user)
{
    using (Context DB = new Context())
    {
        DB.UpdateGraph(user, map => map.AssociatedCollection(u => u.Friends));                
        DB.SaveChanges();
    }
}

可能有一个更复杂的答案,但我是 EF 的新手,这对我有用。

相关文章: