如何在不产生重复的情况下对代码表使用AutoMapper
本文关键字:情况下 代码表 AutoMapper | 更新日期: 2023-09-27 18:27:08
我正在使用automapper将一个数据库导入到一个结构略有不同的新数据库中。我不知道如何处理下面的TargetType这样的代码表。Automapper在导入它们时似乎创建了重复项(db.SaveChanges()上的"无法确定'Models.ShipTarget_TargetType'关系的主体端。多个添加的实体可能具有相同的主键。")。我在多对多关系方面也遇到过同样的问题,但我没有得到错误,因为桥接表允许AutoMapper在不违反任何约束的情况下愉快地创建重复项。
换句话说,当映射ShipTarget(有很多)时,当它映射TargetType字段(只有几个TargetType)时,它总是创建一个新的TargetType,而不是检查它是否已经存在于目标中并使用预先存在的实例。由于TargetType是一个代码表,我希望在多个ShipTargets之间共享特定值的相同实例。
请注意,在调用保存更改之前,所有映射都是一次性完成的。因此,目标数据库中绝对不存在任何TargetType,因此我希望它从源代码表中创建每个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);
的地方
因此,对于引用代码表的类的成员,我告诉它最初忽略该成员,然后使用该条目检查新代码表中是否存在该条目,将其映射到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);
}
}
});