实体框架 4 - AddObject 与 Attach

发布于 2024-09-27 08:44:33 字数 1578 浏览 6 评论 0原文

我最近一直在使用 Entity Framework 4,对于何时使用 有点困惑ObjectSet.AttachObjectSet.AddObject

根据我的理解:

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

因此,如果我创建一个新人,我会这样做。

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

如果我修改现有人员,我会这样做:

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

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

现在,我的问题 - 我还没有找到必须使用附加的场景。

我在这里缺少什么?什么时候我们需要使用Attach?

编辑

只是为了澄清一下,我正在寻找何时使用 Attach 而非 AddObject 的示例(反之亦然)。

编辑2

下面的答案是正确的(我接受了),但我想我会添加另一个例子,其中 Attach 会很有用。

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

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

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

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

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

I have been working with Entity Framework 4 recently, and am slightly confused as to when to use ObjectSet.Attach, and ObjectSet.AddObject.

From my understanding:

  • Use "Attach" when an Entity already exists in the system
  • Use "AddObject" when creating a brand new Entity

So, if i'm creating a new Person, i do this.

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

If i'm modifying an existing Person, i do this:

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

Keep in mind, this is a very simple example. In reality i am using Pure POCO's (no code generation), Repository pattern (don't deal with ctx.Persons), and Unit of Work (don't deal with ctx.SaveChanges). But "under the covers", the above is what happens in my implementation.

Now, my question - I am yet to find a scenario where i have had to use Attach.

What am i missing here? When do we need to use Attach?

EDIT

Just to clarify, i'm looking for examples of when to use Attach over AddObject (or vice-versa).

EDIT 2

The below answer is correct (which i accepted), but thought i'd add another example where Attach would be useful.

In my above example for modifying an existing Person, two queries are actually being executed.

One to retrieve the Person (.SingleOrDefault), and another to perform the UPDATE (.SaveChanges).

If (for some reason), i already knew that "Joe Bloggs" existed in the system, why do an extra query to get him first? I could do this:

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

This will result in just an UPDATE statement being executed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

浮萍、无处依 2024-10-04 08:44:33

ObjectContext.AddObject< /a> 和 ObjectSet.AddObject

AddObject 方法用于添加数据库中存在的新创建的对象。该实体将获得一个自动生成的临时EntityKey及其
EntityState 将设置为已添加。当调用 SaveChanges 时,EF 会清楚该实体需要插入到数据库中。

ObjectContext.AttachObjectSet.Attach

另一方面,Attach 用于数据库中存在的实体。而不是设置
添加 EntityState,附加会产生未更改 EntityState,这意味着它自从附加到上下文以来就没有更改。假定您附加的对象存在于数据库中。如果您在附加对象后对其进行修改,则当您调用 SaveChanges 时,EntityKey 的值将用于通过在数据库表中查找其匹配 ID 来更新(或删除)相应的行。

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

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

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();

ObjectContext.AddObject and ObjectSet.AddObject:

The AddObject method is for adding newly created objects that do not exist in the database. The entity will get an automatically generated temporary EntityKey and its
EntityState will be set to Added. When SaveChanges is called, it will be clear to the EF that this entity needs to be inserted into the database.

ObjectContext.Attach and ObjectSet.Attach:

On the other hand, Attach is used for entities that already exist in the database. Rather than setting the
EntityState to Added, Attach results in an Unchanged EntityState, which means it has not changed since it was attached to the context. Objects that you are attaching are assumed to exist in the database. If you modify the objects after they’ve been attached, when you call SaveChanges the value of the EntityKey is used to update (or delete) the appropriate row by finding its matching ID in the db table.

Furthermore, using the Attach method, you can define relationships between entities that already exist in the ObjectContext but that have not been connected automatically. Basically the main purpose of Attach, is to connect entities that are already attached to the ObjectContext and are not new so you cannot use Attach to attach entities whose EntityState is Added. You have to use Add() in this case.

For example, let's assume your Person entity has a navigation property named Addresses which is a collection of Address entity. Let's say you have read both Objects from context, but they are not related to each other and you want to make it so:

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();
傲性难收 2024-10-04 08:44:33

这是一个迟到的回复,但它可能会帮助其他人找到这个。

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

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”将被断开连接。

我就是这么理解的。

This is a late response but it might help others that find this.

Basically, a "disconnected" entity can happen when you manipulate an entity outside of the "using" scope.

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
}

If you enter another "using" scope then the "e" variable will be disconnected because it belongs to the previous "using" scope and since the previous "using" scope is destroyed then "e" is disconnected.

That's how I understand it.

扎心 2024-10-04 08:44:33

这是编程实体框架:DbContext的引用

对实体调用删除
不被上下文跟踪将导致抛出 InvalidOperationException。这
实体框架抛出此异常,因为不清楚您的实体是否
正在尝试删除的是应标记为删除的现有实体或新实体
应该被忽略的实体。因此,我们不能仅使用Remove来标记
断开连接的实体被视为已删除;我们需要先附加它

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方法来注册
现有的删除目标

This is a quote from Programming Entity Framework: DbContext

Calling Remove on an entity that
isn’t tracked by the context will cause an InvalidOperationException to be thrown. The
Entity Framework throws this exception because it isn’t clear whether the entity you
are trying to remove is an existing entity that should be marked for deletion or a new
entity that should just be ignored. For this reason, we can’t use just Remove to mark a
disconnected entity as Deleted; we need to Attach it first
.

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();
    }
}

The TestDeleteDestination method simulates a client application fetching an existing
Destination from the server and then passing it to the DeleteDestination method on
the server. The DeleteDestination method uses the Attach method to let the context
know that it’s an existing Destination. Then the Remove method is used to register the
existing Destination for deletion

热鲨 2024-10-04 08:44:33

我用过这个方法

var user = _context.Users.Attach(新用户
     {
     名称=“法希梅”,
     电子邮件 = "[电子邮件受保护]",
});
 _context.SaveChanges();

 返回视图(用户);

I used this method

var user = _context.Users.Attach(new User
     {
     Name = "Fahimeh",
     Email = "[email protected]",
});
 _context.SaveChanges();

 return View(user);
瀟灑尐姊 2024-10-04 08:44:33

只引用主键而不附加怎么样?

IE:

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();

What about only refering to the primary key instead of attaching?

i.e:

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文