2012-03-09 34 views
1

我使用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; } 
    ... 
    } 

回答

0

我想做的下方在Tar​​getType的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); 
     } 
     } 
    }); 
相关问题