如何在代码表上使用AutoMapper而不产生重复?
我使用automapper从一个数据库导入到一个结构稍有不同的新数据库中。我不知道如何处理下面的代码表,如TargetType。 Automapper似乎在导入它们时会创建重复项(“无法确定'Models.ShipTarget_TargetType'关系的主体端,多个添加的实体可能具有相同的主键。”on db.SaveChanges())。我也遇到了与多对多关系相同的问题,但是我没有在那里发现错误,因为桥表允许AutoMapper在不违反任何限制的情况下快速创建重复项。如何在代码表上使用AutoMapper而不产生重复?
换句话说,当映射ShipTarget(有很多这些)时,当它映射TargetType字段(只有少数TargetTypes)时,它总是创建一个新的TargetType,而不是检查它是否已经存在于目标中并使用预先存在的实例。由于TargetType是一个代码表,因此我希望同一个实例可以在许多ShipTargets*享一个特定的值。
请注意,在保存更改被调用之前,所有映射都在一次完成。所以目标数据库中绝对没有TargetTypes,所以我期望它会从源代码表中创建一个TargetType,但它会创建重复项,就像每个ShipTarget引用一个唯一的TargetType一样。
我当前的映射是这样的(简化,幸而没有错别字):
var src2NewShip = Mapper.CreateMap<SourceDataModel.Ship, Ship>()
.ForMember(newShp => newShp.Targets, c => c.MapFrom(srcShp => srcShp.ShipTargets));
var srcShipTargetType2NewTargetType = Mapper.CreateMap<SourceDataModel.ShipTargetType, TargetType>();
var srcShipTarget2SrcTarget = Mapper.CreateMap<SourceDataModel.ShipTarget, ShipTarget>()
.ForMember(newTarget => newTarget.TargetType, c => c.MapFrom(srcTarget => srcTarget.ShipTargetType));
我如何确保它只是作为有源数据库ShipTargetTypes,创建多TargetTypes?而不是在被多个ShipTarget引用时复制它们。
这个伪代码表示我有一个想法来解决问题,但是这似乎很令人费解,我不知道究竟是如何得到它的权利,无论如何努力:
var srcShipTarget2SrcTarget = Mapper.CreateMap<SourceDataModel.ShipTarget, ShipTarget>()
.ForMember(newTarget => newTarget.TargetType, c => c.MapFrom(srcTarget =>
{
newDb.Ships.SelectMany(s => s.ShipTargets).FirstOrDefault(st=>st.TargetType.UniqueName == srcTarget.UniqueName);
//here I would return the found instance, or call upon automapper to map srcTarget to a new TargetType and return that
//essentially, use existing, or return new
);
public class TargetType
{
[Key]
public int TargetTypeKey { get; set; }
public string UniqueName { get; set; }
...
}
public class ShipTarget
{
[Key]
public int ShipTargetKey { get; set; }
public int ShipKey { get; set; }
[ForeignKey("ShipKey")]
public Ship Ship { get; set; }
public int TargetTypeKey { get; set; }
[ForeignKey("TargetTypeKey")]
public TargetType TargetType { get; set; }
...
}
public class Ship
{
[Key]
public int ShipKey { get; set; }
public virtual ICollection<ShipTarget> Targets { get; set; }
...
}
我想做的下方在TargetType的ConvertUsing中,这样它就可以应用到引用代码表的任何地方,但我无法弄清楚如何告诉它使用默认映射来创建一个新映射(如果它不存在的话),比如在我在下面做Mapper.Map(srcTarget.ShipTarget, newTarget.TargetType);
因此,对于引用代码表的类的成员,我告诉它最初igno然后将它映射到AfterMap中,方法是检查条目是否存在于新代码表中,使用该条目,如果该条目不存在,则创建一个新条目。
var srcShipTarget2SrcTarget = Mapper.CreateMap<SourceDataModel.ShipTarget, ShipTarget>()
.ForMember(newTarget => newTarget.TargetType, c => c.Ignore())
.AfterMap((srcTarget, newTarget) =>
{
if (srcTarget.ProjectTargetType != null)
{
newTarget.TargetType = db.TargetTypes.FirstOrDefault(tt => tt.UniqueName == odsT.ProjectTargetType.UniqueName);
if (newTarget.TargetType == null)
{
newTarget.TargetType = Mapper.Map(srcTarget.ShipTarget, newTarget.TargetType);
}
}
});