C# 使用AutoMapper重新使用集合属性中的目标实例
我有一个编辑模型和一个EF实体,我想使用AutoMapper用编辑模型中的数据更新实体。这非常有效:C# 使用AutoMapper重新使用集合属性中的目标实例,c#,entity-framework,automapper,C#,Entity Framework,Automapper,我有一个编辑模型和一个EF实体,我想使用AutoMapper用编辑模型中的数据更新实体。这非常有效: // The classes involved public class FooEditModel { public Guid Id { get; set; } public string FooProp { get; set; } } public class FooEntity { public Guid Id { get; set; } public st
// The classes involved
public class FooEditModel {
public Guid Id { get; set; }
public string FooProp { get; set; }
}
public class FooEntity {
public Guid Id { get; set; }
public string FooProp { get; set; }
}
// Mapper configuration
cfg.CreateMap<FooEditModel, FooEntity>();
// Actual usage
var entity = _dbContext.Foos
.Where(e => e.Id == id) // id is a route param
.Single();
_mapper.Map(editModel, entity); // editModel is populated by model binding
_dbContext.SaveChanges();
现在,它没有更新footentity
以及所有相关的BarEntity
s,而是给我一个InvalidOperationException
,并显示以下消息:
InvalidOperationException:无法跟踪实体类型“BarEntity”的实例,因为已在跟踪具有相同密钥的此类型的另一个实例。添加新实体时,对于大多数键类型,如果未设置键(即,如果为键属性指定了其类型的默认值),则将创建唯一的临时键值。如果要显式设置新实体的键值,请确保它们不会与现有实体或为其他新实体生成的临时值冲突。附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文
如何配置AutoMapper,使映射程序可以重新使用现有集合中的对象,而不是尝试替换它们?
你应该了解引擎盖下发生了什么。AutoMapper是一个简单的工具,它使用反射来避免逐行重写属性。尽管如此,它还是在不使用集合的情况下不时创建新对象(如您使用集合的示例中)。映射程序并没有创建任何东西—它只是重写属性。如果您添加集合,他将通过创建新集合来从editModel映射新集合来处理此问题
这会造成这样一种情况:在DataContext上,您已经实例化了Bar类型的对象,而mapper正在创建一个新的对象,这会导致冲突
正如Ivan Stoev所说,您可以使用Automapper.Collection来处理这种情况(虽然我从未使用过它,但它可能解决了这个问题)看看package.Automapper.Collection确实解决了这个问题-谢谢(您和Ivan)!起初,我在让它工作时遇到了一些麻烦,但结果证明这主要是因为它对配置提出了一些要求,这些要求在使用AutoMapper.Attributes时很难满足,所以我放弃了后者,现在它可以工作了。
// 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();