如何在分离的实体框架4.1 POCO实体上保存更新的多对多集合

本文关键字:实体 保存 更新 集合 POCO 分离 框架 | 更新日期: 2023-09-27 18:16:56

在过去的几天里,我试图正确地更新我的POCO实体。更具体地说,它是多对多关系集合。

我有三个数据库表:作者- 1..n - AuthorBooks - n..1 - Books.

转换成两个POCO实体:具有Books集合的Author实体和具有Authors集合的Book实体。

<<p> 案例/strong>

当我有一个活动DbContext,检索Book实体,添加Author并调用SaveChanges()时,更改被正确地发送到数据库。到目前为止一切正常。

然而,我有一个桌面应用程序,DbContext生命周期有限,如下面的代码片段所示。

public Book GetBook(int id)
{
   using (var context = new LibariesContext())
   {
      return context.Books
         .Include(b => b.Authors)
         .AsNoTracking()
         .Single(b => b.BookId == id);
   }
}
public Author GetAuthor(int id)
{
   using (var context = new LibariesContext())
   {
      return context.Authors
         .AsNoTracking()
         .Single(a => a.AuthorId == id);
   }
}

我的各种业务逻辑方法的简化示例,将其封装在一起:

public void BusinessLogicMethods()
{
   Book book = GetBook(id: 1);
   Author author = GetAuthor(id: 1);
   book.Name = "New book title";
   book.Authors.Add(author);
   SaveBook(book);
}
public void SaveBook(Book book)
{
   using (var context = new LibariesContext())
   {
      context.Entry(book).State = System.Data.EntityState.Modified;
      context.SaveChanges();
   }
}

不幸的是,这里唯一真正保存的是书的名字。没有保存新作者,也没有抛出异常。

  • 保存分离实体的集合的最佳方法是什么?
  • 有解决这个问题的方法吗?

如何在分离的实体框架4.1 POCO实体上保存更新的多对多集合

我也是EF 4.1的新手,如果我正确理解你的问题,我想我在周末遇到了这种胡说八道。在尝试了太阳下的每一种方法来更新条目后,我在SO上找到了一个咒语(我再也找不到它了),并把它变成了一个通用的扩展方法。现在,在

这行之后
book.Authors.Add(author);

我会加上这行:

context.UpdateManyToMany(book, b => b.Authors)

你可能需要重构你的代码来实现这一点。

无论如何……这是我写的扩展方法。让我知道它是否有效(不保证!!)

    public static void UpdateManyToMany<TSingle, TMany>(
        this DbContext ctx,
        TSingle localItem,
        Func<TSingle, ICollection<TMany>> collectionSelector)
        where TSingle : class
        where TMany : class
    {
        DbSet<TSingle> localItemDbSet = ctx.Set(typeof(TSingle)).Cast<TSingle>();
        DbSet<TMany> manyItemDbSet = ctx.Set(typeof(TMany)).Cast<TMany>();
        ObjectContext objectContext = ((IObjectContextAdapter) ctx).ObjectContext;
        ObjectSet<TSingle> tempSet = objectContext.CreateObjectSet<TSingle>();
        IEnumerable<string> localItemKeyNames = tempSet.EntitySet.ElementType.KeyMembers.Select(k => k.Name);
        var localItemKeysArray = localItemKeyNames.Select(kn => typeof(TSingle).GetProperty(kn).GetValue(localItem, null));
        localItemDbSet.Load();
        TSingle dbVerOfLocalItem = localItemDbSet.Find(localItemKeysArray.ToArray());
        IEnumerable<TMany> localCol = collectionSelector(localItem)?? Enumerable.Empty<TMany>();
        ICollection<TMany> dbColl = collectionSelector(dbVerOfLocalItem);
        dbColl.Clear();
        ObjectSet<TMany> tempSet1 = objectContext.CreateObjectSet<TMany>();
        IEnumerable<string> collectionKeyNames = tempSet1.EntitySet.ElementType.KeyMembers.Select(k => k.Name);
        var selectedDbCats = localCol
            .Select(c => collectionKeyNames.Select(kn => typeof (TMany).GetProperty(kn).GetValue(c, null)).ToArray())
            .Select(manyItemDbSet.Find);
        foreach (TMany xx in selectedDbCats)
        {
            dbColl.Add(xx);
        }
        ctx.Entry(dbVerOfLocalItem).CurrentValues.SetValues(localItem);
    }

我在试图解决同样的问题时遇到了这个问题。最后,我采取了一种不同的方法,似乎是有效的。我不得不在实体上公开一个"状态"属性,并让调用上下文设置对象图中实体的状态。

这减少了web服务/数据上下文端确定更改内容的开销,因为图可以由任意数量的查询渗透填充。还有一个名为GraphDiff的NuGet包,它可能也适用于您(详细信息见下面的链接)。

总之,这里有完整的细节:http://sanderstechnology.com/2013/solving-the-detached-many-to-many-problem-with-the-entity-framework/12505/