【问题标题】:Unable to attach an existing object in Entity Framework 6无法在 Entity Framework 6 中附加现有对象
【发布时间】:2015-10-16 03:51:54
【问题描述】:

我有一堂课Customer。我正在尝试克隆 Customer 对象并对其进行修改,然后我希望将这些修改反映在上下文中(也包括数据库)。我正在使用以下代码来做到这一点。

    Customer old = context.Customers.Where(c=>c.CustomerID ==1 ).SingleOrDefault();
    Customer m = CustomExtensions.ShallowCopyEntity<Customer>(old);
    m.Name = "Modified";
    m.MobileNo = "9999999999";

    context.Customers.Attach(m);

但它抛出以下异常

附加“DataBindingSample.Customer”类型的实体 失败,因为相同类型的另一个实体已经具有相同的 主键值。使用“附加”方法或 将实体的状态设置为“未更改”或“已修改”(如果有) 图中的实体具有冲突的键值。这可能是因为 一些实体是新实体,尚未收到数据库生成的密钥 价值观。在这种情况下,使用“添加”方法或“添加”实体状态 跟踪图,然后将非新实体的状态设置为 “未更改”或“已修改”(视情况而定)。

我尝试将EntityState 更改为Modified,但没有成功。

谁能告诉我如何做到这一点?

我的主要目标是

  1. 我想克隆(必要时我将使用深度克隆)现有实体
  2. 想要修改克隆的实体(以及引用的实体 - 在这种情况下我将使用深度克隆)
  3. 最后我想保存对数据库的更改

编辑

正如this 评论中指出的那样,我正在尝试附加上下文中存在的对象。因此,如果必须附加,我可以先将其分离,然后再次附加,如下所示。

        Customer old = context.Customers.Where(c=>c.CustomerID ==1 ).SingleOrDefault();
        Customer m = CustomExtensions.ShallowCopyEntity<Customer>(old);
        m.Name = "Modified789789";
        m.MobileNo = "9999999999";
        ((IObjectContextAdapter)context).ObjectContext.Detach(old);
        context.Customers.Attach(m);
        context.Entry(m).State = EntityState.Modified;
        context.SaveChanges();

否则我可以按照this答案中提到的2个选项。

【问题讨论】:

  • 在尝试保存之前,您是否尝试为克隆提供新的主键值?
  • @jstreet,不,实际上它不是一个新对象,我想修改一个现有对象。如果我给新的主键它没有意义。
  • 问题是,当您克隆现有对象时,它是一个新对象,需要自己的主键。如果您只想修改现有对象,则不应克隆它。你不能同时拥有它。
  • 我不明白你为什么要克隆它。根据定义,克隆创造了一些新的东西。它不会修改它。
  • @dman2306 我克隆它的原因是,我以用户将进行所有修改的形式显示客户,这里所有的修改都反映在上下文中(数据绑定)。但是如果用户选择取消所有修改它是不可能的。所以我正在克隆它,以便所有修改都将在克隆对象上完成,如果用户选择保存,最后克隆的对象将被保存。

标签: c# entity-framework


【解决方案1】:

我能想到的有两种选择:

  1. 将更新后的值复制回加载到 DbContext 中的原始实体,然后保存更改。
  2. 更新原始实体的值,然后在用户取消更新时将其丢弃。

选项 1

只需将更新后的值复制回最初加载的实体即可。 Automapper 是您从事此类任务的朋友。以后可以扩展此方法,以允许用户更改实体的模型,而不是数据层对象本身(例如,公开用户可以编辑的有限数量的字段)。

var entity = context.Customers.SingleOrDefault(c => c.CustomerID == 1);
var updatedEntity = CustomExtensions.ShallowCopyEntity<Customer>(old);

updatedEntity.Name = "Modified";
updatedEntity.MobileNo = "9999999999";

entity.Name = updatedEntity.Name;
entity.MobileNo = updatedEntity.MobileNo;

context.SaveChanges();

如果您添加 Automapper nuget,那么您的映射(复制)将变得更加容易:

Mapper.CreateMap<Customer, Customer>();
Mapper.Map(updatedEntity, entity);

您的代码将如下所示:

// Configuring mapping. Needs to be done only once.
Mapper.CreateMap<Customer, Customer>();

var entity = context.Customers.SingleOrDefault(c => c.CustomerID == 1);

// Check if entity is null

var updatedEntity = CustomExtensions.ShallowCopyEntity<Customer>(old);

updatedEntity.Name = "Modified";
updatedEntity.MobileNo = "9999999999";

// Copy the updated values back
Mapper.Map(updatedEntity, entity);

context.SaveChanges();

选项 2

如果用户改变主意并取消,则对最初加载的实体进行更改并丢弃它们。请参阅this 帖子和this 帖子了解如何操作。 如果您仍然需要它,丢弃整个 DbContext 可能不是一个好选择(duh)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-13
    • 2015-11-09
    • 2016-08-08
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多