使用AutoMapper在集合属性中重用目标实例

时间:2017-08-01 10:46:44

标签: c# entity-framework automapper

我有一个编辑模型和一个EF实体,我想使用AutoMapper用编辑模型中的数据更新实体。这非常有效:

FooProp

现在,editModel已使用// classes pulic class FooEditModel { public Guid Id { get; set; } public IReadOnlyCollection<BarEditModel> Bars { get; set; } } public class BarEditModel { public Guid Id { get; set; } public string BarProp { get; set; } } public class FooEntity { public Guid Id { get; set; } public IReadOnlyCollection<BarEntity> Bars { get; set; } } public class BarEntity { public string BarProp { get; set; } } // mapper config cfg.CreateMap<FooEditModel, FooEntity>(); cfg.CreateMap<BarEditModel, BarEntity>(); // usage var entity = _dbContext.Foos .Include(f => f.Bars) .Where(f => f.id == id) .Single(); _mapper.Map(editModel, entity); _dbContext.SaveChanges(); FooEntity的值进行了更新。一切都很好。

然而,当我添加一个不同类型的集合时,它不再像我想的那样好用

BarEntity

现在,它不是更新InvalidOperationException以及所有相关的{{1}},而是给我一个{{1}},其中包含以下消息:

  

InvalidOperationException:无法跟踪实体类型“BarEntity”的实例,因为已经跟踪了具有相同键的此类型的另一个实例。添加新实体时,对于大多数密钥类型,如果未设置密钥,则将创建唯一的临时密钥值(即,如果为密钥属性指定了其类型的默认值)。如果要为新实体显式设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突。附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。

如何配置AutoMapper,以便映射器可以重用现有集合中的对象,而不是尝试替换它们?

1 个答案:

答案 0 :(得分:2)

托马斯

你应该了解幕后发生的事情。 AutoMapper是一个简单的工具,它使用反射来避免逐行属性重写。然而,它不时地创建新对象(如在带有集合的示例中)没有集合,映射器不会创建任何东西 - 它只是重写属性。如果添加集合,他将通过创建新集合来处理此问题,以从editModel映射新集合。

这会创建一种情况,在DataContext上,您实例化了Bar类型的对象,mapper正在创建一个导致冲突的新对象。

正如Ivan Stoev所说,您可以使用Automapper.Collection来处理这种情况(我从未使用它,但它可能解决了这个问题)