在Persist.InsertOrUpdate

时间:2017-06-12 22:06:42

标签: c# entity-framework automapper

我正在使用AutoMapper并尝试AutoMapper.Collection.EntityFramework,特别是Persist<T>方法。

我的“来源”是一个相当大的对象图,已经(通过AutoMapper)转换为一些EntityFramework个实体。父实体名为Log

在我的实验测试中,我执行以下操作:

var mapper = collectionConfig.CreateMapper();
var persistence = dbContext.Logs.Persist(mapper);
var testLog = logs.First();  // "logs" is the output of an AutoMapper.Map of a collection.
persistence.InsertOrUpdate<Log>(testLog);

Assert.IsTrue(dbContext.ChangeTracker.HasChanges());

ChangeTracker.HasChanges来电时会发生异常:

  

System.InvalidOperationException:属性“Id”是其中的一部分   对象的关键信息,不能修改。

堆栈跟踪是:

  

System.Data.Entity.Core.Objects.EntityEntry.DetectChangesInProperty(的Int32   ordinal,Boolean detectOnlyComplexProperties,Boolean detectOnly)
    在   System.Data.Entity.Core.Objects.EntityEntry.DetectChangesInProperties(布尔   detectOnlyComplexProperties)at   System.Data.Entity.Core.Objects.ObjectStateManager.DetectChangesInScalarAndComplexProperties(IList`1   条目)   System.Data.Entity.Core.Objects.ObjectStateManager.DetectChanges()
  在System.Data.Entity.Core.Objects.ObjectContext.DetectChanges()at   System.Data.Entity.Internal.InternalContext.DetectChanges(布尔   强迫)   System.Data.Entity.Infrastructure.DbChangeTracker.HasChanges()

这是一个众所周知且记录良好的异常:它发生在您拥有现有EntityFramework实体对象并尝试更改其主键属性字段之一的值时。

但我不会在任何地方这样做。

我从未在代码中的任何位置设置Id值。 (Id属性的值来自其他地方,并且在创建AutoMapper对象列表时由Log设置。由于数据的性质,我有理由相信数据库中已存在testLog对象的条目。)

我已经能够通过LogAutoMapper创建的EF条目的全部集合保存到数据库中,所以我不认为我的Log实体或对象图有问题。我认为这是AutoMapper.Collection.EntityFramework以某种方式做的事情。

我确实尝试了Persist方法,使用了一个不同的,更简单的实体,子实体更少,并且没有这个问题。但我甚至无法从这个错误中判断出图中的哪个对象具有所谓的更改Id值:此对象图中的一半对象具有一个名为Id的主键。

我可以确认testLog.Id未更改InsertOrUpdate的实际。但是,我尝试检查Entry<Log> testLog甚至查看dbContext.Logs.Local都会导致同样的异常被抛出。

所以:任何人都知道为什么会这样?

1 个答案:

答案 0 :(得分:0)

感谢AutoMapper.CollectionTyler Carlson,我有一个答案。

persistence.InsertOrUpdate<Log>(testLog);

问题源于testLog已经属于Log类型,这与我在EntityFramework中使用的类型相同。正如泰勒所说:

  

Automapper不支持映射到自身,因为它导致了很多   问题。   [...]
  你应该做的就是过世   dto进入持久调用,而不是它映射到的实体。那   映射将在InsertOrUpdate调用中发生。

我们还发现,如果您的EntityDto对象共享一个公共基类,并且该基类包含关键字段的定义,那么也会发生这种情况。

所以在我的情况下,我的EntityDto包含95%的相同字段,来自一个公共基类,我不得不采用Id属性主键出基类,并在两个类中单独定义。这确保了虽然属性具有相同的名称,但从Reflection的角度来看,它们在任何意义上都不具有相同的属性。

如果您对详细信息感到好奇,可以在此处讨论:AutoMapper.Collection Issue 40