我有一个编辑模型和一个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,以便映射器可以重用现有集合中的对象,而不是尝试替换它们?
答案 0 :(得分:2)
托马斯
你应该了解幕后发生的事情。 AutoMapper是一个简单的工具,它使用反射来避免逐行属性重写。然而,它不时地创建新对象(如在带有集合的示例中)没有集合,映射器不会创建任何东西 - 它只是重写属性。如果添加集合,他将通过创建新集合来处理此问题,以从editModel映射新集合。
这会创建一种情况,在DataContext上,您实例化了Bar类型的对象,mapper正在创建一个导致冲突的新对象。
正如Ivan Stoev所说,您可以使用Automapper.Collection来处理这种情况(我从未使用它,但它可能解决了这个问题)