我正在使用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
对象的条目。)
我已经能够通过Log
将AutoMapper
创建的EF
条目的全部集合保存到数据库中,所以我不认为我的Log
实体或对象图有问题。我认为这是AutoMapper.Collection.EntityFramework
以某种方式做的事情。
我确实尝试了Persist
方法,使用了一个不同的,更简单的实体,子实体更少,并且没有这个问题。但我甚至无法从这个错误中判断出图中的哪个对象具有所谓的更改Id
值:此对象图中的一半对象具有一个名为Id
的主键。
我可以确认testLog.Id
未更改InsertOrUpdate
的实际值。但是,我尝试检查Entry<Log>
testLog
甚至查看dbContext.Logs.Local
都会导致同样的异常被抛出。
所以:任何人都知道为什么会这样?
答案 0 :(得分:0)
感谢AutoMapper.Collection
的Tyler Carlson
,我有一个答案。
persistence.InsertOrUpdate<Log>(testLog);
问题源于testLog
已经属于Log
类型,这与我在EntityFramework
中使用的类型相同。正如泰勒所说:
Automapper不支持映射到自身,因为它导致了很多 问题。 [...]
你应该做的就是过世 dto进入持久调用,而不是它映射到的实体。那 映射将在InsertOrUpdate调用中发生。
我们还发现,如果您的Entity
和Dto
对象共享一个公共基类,并且该基类包含关键字段的定义,那么也会发生这种情况。
所以在我的情况下,我的Entity
和Dto
包含95%的相同字段,来自一个公共基类,我不得不采用Id
属性主键出基类,并在两个类中单独定义。这确保了虽然属性具有相同的名称,但从Reflection
的角度来看,它们在任何意义上都不具有相同的属性。
如果您对详细信息感到好奇,可以在此处讨论:AutoMapper.Collection Issue 40。