【发布时间】:2014-03-18 03:49:29
【问题描述】:
我正在构建一个 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。这不可能。
【问题讨论】:
-
我在附加到 POCO.Lesson 之前更改了测试 localLesson = context.lessons.Find(myObject.ID);它返回true,所以它不附加。没有更多的例外,但我回到它创建一个新的单元、课程和程序,而不是使用现有的。我接近尝试将附件包含在 try catch 中的绝望方法,这可能行不通(它不会附加,因此会创建新实体)。
-
这太令人沮丧了,这不可能这么难。
-
如果使用通用的存储库模式会容易得多。
-
这里的问题 - 可能是一个问题,是我添加的一些单词是新的,一些存在,还有一些被更改(它们的父级更改)。所有单元都存在,课程和计划也是如此。所以我需要附加现有实体以避免创建其他实体,并且(我认为这是一个问题)对象图包含机器人新实体和现有实体的路径。
-
通用存储库模式看起来不错,但如果我无法弄清楚实体框架的这种简单用法,我不会转向更复杂的模式。