首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >实体框架4- AddObject vs Attach

实体框架4- AddObject vs Attach
EN

Stack Overflow用户
提问于 2010-10-13 08:59:05
回答 5查看 94.3K关注 0票数 135

我最近一直在使用Entity Framework4,对于何时使用ObjectSet.AttachObjectSet.AddObject有些困惑。

据我所知:

  • 当系统中已存在实体时使用"Attach“

在创建全新实体时使用"AddObject”

所以,如果我创建了一个新的Person,我会这样做。

代码语言:javascript
复制
var ctx = new MyEntities();
var newPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.AddObject(newPerson);
ctx.SaveChanges();

如果我正在修改一个现有的Person,我会这样做:

代码语言:javascript
复制
var ctx = new MyEntities();
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
existingPerson.Name = "Joe Briggs";
ctx.SaveChanges();

请记住,这是一个非常简单的示例。实际上,我使用的是Pure POCO(无代码生成)、存储库模式(不处理ctx.Persons)和工作单元(不处理ctx.SaveChanges)。但“在幕后”,以上就是在我的实现中发生的事情。

现在,我的问题是-我还没有找到一个我必须使用Attach的场景。

这里我漏掉了什么?什么时候需要使用Attach?

编辑

为了澄清,我正在寻找何时通过AddObject使用Attach的示例(反之亦然)。

编辑2个

下面的答案是正确的(我接受了),但我认为我应该添加另一个示例,其中Attach将是有用的。

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

一个用于检索人员(.SingleOrDefault),另一个用于执行更新(.SaveChanges)。

如果(出于某种原因),我已经知道"Joe Bloggs“存在于系统中,为什么要先查询他呢?我可以这样做:

代码语言:javascript
复制
var ctx = new MyEntities();
var existingPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.Attach(existingPerson);
ctx.SaveChanges();

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

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-10-13 09:27:24

和:

AddObject方法用于添加新创建的对象,这些对象不支持数据库中的。实体将获得一个自动生成的临时EntityKey,其EntityState将被设置为Added。当调用SaveChanges时,EF将清楚地知道该实体需要插入到数据库中。

和:

另一方面,Attach用于已经存在于数据库中的的实体。Attach不是将EntityState设置为Added,而是生成一个未更改的EntityState,这意味着它在附加到上下文后没有更改。假定要附加的对象存在于数据库中。如果在附加对象之后对其进行修改,则在调用SaveChanges时,EntityKey的值用于通过在db表中查找匹配的ID来更新(或删除)适当的行。

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

例如,假设您的Person实体有一个名为Addresses的导航属性,它是Address实体的集合。假设您已经从上下文中读取了这两个对象,但它们彼此不相关,并且您希望这样做:

代码语言:javascript
复制
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();
票数 167
EN

Stack Overflow用户

发布于 2012-08-02 02:03:52

这是一个较晚的回应,但它可能会帮助其他人找到这一点。

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

代码语言:javascript
复制
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“断开连接。

这就是我的理解。

票数 33
EN

Stack Overflow用户

发布于 2014-07-30 11:19:22

这是Programming Entity Framework: DbContext的一句话

在上下文未跟踪的实体上调用Remove将导致抛出InvalidOperationException。Entity Framework会抛出此异常,因为不清楚您尝试移除的实体是应该标记为删除的现有实体还是应该忽略的新实体。由于这个原因,我们不能只使用来将断开连接的实体标记为已删除;我们需要首先将其附加到

代码语言:javascript
复制
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方法。DeleteDestination方法使用Attach方法让上下文知道它是一个现有的目的地。然后使用Remove方法注册要删除的现有目标

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3920111

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档