实体框架4-AddObject vs Attach

我最近一直在使用实体框架4,对于什么时候使用 ObjectSet 附件AddObject,我有点困惑。

据我所知:

  • 当系统中已经存在一个实体时,请使用“ Attach”
  • 创建全新实体时使用“ AddObject”

所以,如果我是 创建一个新的 Person我就这么做。

var ctx = new MyEntities();
var newPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.AddObject(newPerson);
ctx.SaveChanges();

如果我是 修改现有的 Person,我会这样做:

var ctx = new MyEntities();
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
existingPerson.Name = "Joe Briggs";
ctx.SaveChanges();

请记住,这是一个 很简单示例。实际上,我使用的是 Pure POCO (不生成代码) ,Repository 模式(不处理 ctx)。人员)和工作单位(不要处理 ctx。保存更改)。但是“在掩护之下”,以上就是在我的实现中发生的事情。

现在,我的问题 -我还没有找到使用 接上的场景。

我错过了什么? 我们什么时候需要使用附加?

剪辑

只是为了澄清,我正在寻找 例子的时候使用附加超过添加对象(或反之亦然)。

编辑2

下面的答案是正确的(我接受) ,但认为我会添加另一个例子,附加将是有用的。

在上面的 修改现有的 Person示例中,实际执行了两个查询。

一个用于检索 Person (. SingleOrDefault) ,另一个用于执行 UPDATE (. SaveChanges)。

如果(出于某种原因) ,我已经知道系统中存在“ Joe Bloggs”,为什么要做额外的查询来获得他第一?我可以这么做:

var ctx = new MyEntities();
var existingPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.Attach(existingPerson);
ctx.SaveChanges();

这将导致只执行一个 UPDATE 语句。

95436 次浏览

AddObject ObjectSet. AddObject < a href = “ http://msdn.microsoft.com/en-us/library/dd487277.aspx”rel = “ noReferrer”> ObjectSet. AddObject :
AddObject方法用于添加新创建的对象,这些对象在数据库中存在 不是。该实体将获得自动生成的临时 EntityKey及其 EntityState 将设置为 补充。当调用 SaveChanges 时,EF 会清楚地看到这个实体需要插入到数据库中。

附加 < strong > ObjectSet. Attach :
另一方面,接上用于数据库中已经有 存在的实体 EntityState to Add,Attach 会生成一个 没变 EntityState,这意味着它自从附加到上下文以来没有发生更改。假定您所附加的对象在数据库中存在。如果在附加对象之后修改它们,那么在调用 SaveChanges 时,EntityKey 的值将用于通过在 db 表中找到与其匹配的 ID 来更新(或删除)适当的行。

此外,使用 Attach 方法,您可以定义 ObjectContext 中已经存在但是已经自动连接了 不是的实体之间的关系。基本上,Attach 的主要用途是连接已经附加到 ObjectContext 并且是 没有新的实体,因此不能使用 Attach 附加其 EntityState 已添加的实体。在这种情况下必须使用 Add ()

例如,假设 Person 实体具有一个名为 地址的导航属性,它是 地址实体的集合。假设您已经从上下文中阅读了这两个对象,但是它们彼此之间没有关联,因此您希望这样做:

var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID);
existingPerson.Addresses.Attach(myAddress);
// OR:
myAddress.PersonReference.Attach(existingPerson)
ctx.SaveChanges();

如果只引用主键而不是附加主键会怎样?

即:

var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID);
existingPerson.AddressId = myAddress.Id // not -> existingPerson.Addresses.Attach(myAddress);
// OR:
myAddress.Person.Id = existingPerson.Id // not -> myAddress.PersonReference.Attach(existingPerson);
ctx.SaveChanges();

这是一个迟到的反应,但它可能有助于其他人发现这一点。

基本上,当您操作“ using”范围之外的实体时,可能会发生“断开连接”的实体。

Employee e = null;


using (var ctx = new MyModelContainer())
{
e = ctx.Employees.SingleOrDefault(emp => emp .....);
}


using (var ctx2 = new MyModelContainer())
{
e; // This entity instance is disconnected from ctx2
}

如果您输入另一个“ using”作用域,那么“ e”变量将被断开连接,因为它属于前一个“ using”作用域,而且由于前一个“ using”作用域被销毁,因此“ e”将被断开连接。

我是这么理解的。

这是引自 编程实体框架: DbContext的一段话

对一个实体调用 Remove 将导致抛出 InvalidOperationException 实体框架引发此异常,因为不清楚 正试图删除的是应标记为删除的现有实体或新的 由于这个原因,< strong > 我们不能仅仅使用 delete 来标记 a 断开连接的实体作为删除; 我们需要首先附加它 .

private static void TestDeleteDestination()
{
Destination canyon;
using (var context = new BreakAwayContext())
{
canyon = (from d in context.Destinations
where d.Name == "Grand Canyon"
select d).Single();
}
DeleteDestination(canyon);
}
private static void DeleteDestination(Destination destination)
{
using (var context = new BreakAwayContext())
{
context.Destinations.Attach(destination);
context.Destinations.Remove(destination);
context.SaveChanges();
}
}

TestDeleteDestination 方法模拟客户端应用程序获取现有 目标,然后将其传递给 DeleteDestination 方法使用 Attach 方法让上下文 知道它是一个已存在的目的地。然后,移除方法用于注册 现有的删除目的地

我用了这个方法

var user = _context.Users.Attach(new User
{
Name = "Fahimeh",
Email = "text@mail.com",
});
_context.SaveChanges();


return View(user);