c# - 无法附加 Entity Framework 6 中的现有对象

标签 c# entity-framework

我有一个类Customer。我正在尝试克隆 Customer 对象并修改它,然后我希望这些修改反射(reflect)在上下文中(也包括数据库)。我正在使用以下代码来执行此操作。

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

但它抛出以下异常

Attaching an entity of type 'DataBindingSample.Customer' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

我尝试将 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个选项回答。

最佳答案

我能想到两种选择:

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

选项 1

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

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 可能不是一个好的选择(废话)。

关于c# - 无法附加 Entity Framework 6 中的现有对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31628060/

相关文章:

c# - WCF、NetTcpBinding、Streamed 传输模式可以双工吗?

c# - 如何更改此设计以避免沮丧?

c# - SaveChanges 后如何从数据库更新缓存的 EF?

c# - Entity Framework Core 读取和更新多行 - 复合主键

c# - 带桥接表的数据库优先,如何将其排除在模型之外

c# - .NET Core 2 EF,对象引用为空

c# - 如何禁用 EF 代码优先中链接表的级联删除?

c# - Resharper 和 C# Catch 子句

c# - AutoFixture.AutoMoq 为一个构造函数参数提供一个已知值

c# - 单元格事件参数中的动态 DataGridView 引用