如何在分离的实体框架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();
}
}
不幸的是,这里唯一真正保存的是书的名字。没有保存新作者,也没有抛出异常。
- 保存分离实体的集合的最佳方法是什么?
- 有解决这个问题的方法吗?
我也是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/