实体框架附加:具有相同键的对象存在
本文关键字:对象 存在 框架 实体 | 更新日期: 2023-09-27 17:50:39
我正在构建一个windows窗体应用程序,并且我使用多个DBContext实例(大多数情况下每个业务层调用一个)。
在处理一个问题几天之后(当插入新实体时,它们引用的实体被添加为新实体,而不是使用现有实体),我发现问题是我必须将现有实体附加到上下文。
一切都很好,大约2小时,当我在附加时出现错误:具有相同键的实体存在于上下文中。
我试着测试之前附加(类似的方法为每个实体类型):
private void attachIfNeeded(POCO.Program myObject, myContext context)
{
if (!context.Set<POCO.Program>().Local.Any(e => e.ID == myObject.ID))
{
context.programs.Attach(myObject);
return true;
}
else
{
myObject = context.Set<POCO.Program>().Local.Single(e => e.ID == myObject.ID);
return false;
}
}
但是测试返回false,但是当附加时仍然失败。
基本上,如果我不附加,它会添加一个新的实体,而不是使用现有的(和预期的)实体。如果我附加了,会有一个错误,我无法解决。
我环顾四周(现在一整天都在做这件事),我实际上(认为我)知道问题是什么了:
我要添加的实体有多个关系,其他实体可以通过多个路径到达。这会导致问题吗?
请帮忙解决这个问题,那里的解决方案对我来说真的没有意义,也没有奏效。
我真的很接近我将尝试在附加语句周围捕获并完成它的点。但是我会讨厌这样做的。
这里是我的实体(不是全部,但这应该足够了):
public class Word
{
[Key]
public int ID {get;set;}
[Required]
public string word { get; set; }
public WordCategories category { get; set; }
public Word parent {get;set;}
public List<Unit> units { get; set; }
public Program program { get; set; }
public List<Lesson> lessons { get; set; }
public Word()
{
units = new List<Unit>();
lessons = new List<Lesson>();
}
}
public class Unit
{
[Key ]
public int ID { get; set; }
[Required]
public string name { get; set; }
public string description { get; set; }
public List<Lesson> lessons { get; set; }
public Program program {get;set;}
public List<Word> words { get; set; }
public Unit()
{
lessons=new List<Lesson>();
words = new List<Word>();
}
}
这里是我调用attach方法的地方。在第一个附加上抛出错误:
public int addWords(List<POCO.Word > words,int programID, int unitID,int lessonID)
{
CourseHelperDBContext context = getcontext();
int result;
foreach(POCO.Word a in words)
{
foreach (POCO.Unit b in a.units)
attachIfNeeded(b, context);
foreach(POCO.Lesson c in a.lessons )
attachIfNeeded(c,context);
attachIfNeeded(a.program,context);
if (a.parent != null)
attachIfNeeded(a.parent,context);
}
context.words.AddRange(words);
result = context.SaveChanges();
return result;
}
我真不敢相信我有这么多问题。我只是想存储这些实体,添加一些(我还没有达到要更改它们的地步)并保存它。
到目前为止,我想:
- 有些词是新的,有些存在,有些是改变的(主要是父属性);
- 所有单元都存在,程序和课程也存在(所以我需要附加它们);
- 对象图包含多个到实体的路径,其中一些已经存在,一些是新的;
- 我正在为每个请求使用一个新的上下文。当我一直使用相同的东西时,我遇到了其他问题。我找到了指向这种模式的解决方案,我认为这是可以的,因为这就是你在ASP MVC项目上所做的。
所有这些都可能引起问题,但我不知道是哪些问题,也不知道如何解决。
我想我可以通过每次添加一个单词,每次拉出程序,课程和单元来完成这个工作……但这意味着要多次往返DB。不可能是这样的
过了一段时间后回到这个问题,这个例子中的问题是我需要检索存在于我的关系中的实体。
解决方案既不是附加(因为如果实体已经附加,它将失败)也不是添加(因为它已经存在于DB上)。
我应该做的是检索与我正在添加的实体相关的每个实体。
这帮助:实体框架创建与现有实体有关系的新实体,导致试图创建现有实体的新副本
添加实体后,尝试将实体状态设置为modified
context.programs.Attach(myObject);
context.Entry(myObject).State = EntityState.Modified;
我认为你的测试逻辑有错误。
如果数据库中不存在实体,应该添加而不是附加。你的代码是附加的,如果它不能找到一个实体,当它真的应该添加。
添加新实体(创建/插入)的代码
context.Set<T>.Add(entity);
附加实体(Update)的代码
context.Set<T>.Attach(entity);
context.Entry(entity).State = EntityState.Modified;
如果你的代码在第一个附加上失败,那将是attachIfNeeded(b,context);? 我想你没有给我们看这个的代码。
我也有同样的例外。首先,这是我的代码:
public void UpdateBulk(IEnumerable<Position> pDokumentPosition, DbDal pCtx)
{
foreach (Position vPos in pDokumentPosition)
{
vPos.LastDateChanged = DateTime.Now;
pCtx.Entry(vPos).State = EntityState.Modified;
}
pCtx.SaveChanges();
}
我在EntityState上得到了相同的异常。行修改。
在我的例子中,问题是,当将vPos状态设置为modified时,所有相关对象(vPos)都将被删除。文档和vpos . product)以未改变的状态加载到上下文中。在每一步前,它不做任何例外,只是在第二步,因为eg。相关的文档实体已经加载到内存/上下文中(所以文档的关键属性也是)。
我怎么解决它?(也许不是最好的解决方案):
我将每一步中的相关实体拆分为以下行:
if (vPos.Dokument != null)
{
pCtx.Entry(vPos.Dokument).State = EntityState.Detached;
}
if (vPos.Produkt!=null)
{
pCtx.Entry(vPos.Produkt).State = EntityState.Detached;
}
如果你有更好的解决方案,我很期待。
你可以试试这个
context.words.Add(words);
result=context.SaveChanges();