2015-10-17 63 views
0

全部。例如,我们有这样一个简单的类未映射嵌套集合内的Automapper无法正常工作

public class SimpleModel 
{ 
    public int PropertyId { get; set; } 

    public ICollection<SimpleModelCollectionItem> SimpleCollection { get; set; } 
} 

public class SimpleModelCollectionItem 
{ 
    public int PropertyId { get; set; } 
} 

public class SimpleEntity 
{ 
    public int Id { get; set; } 
    public int PropertyId { get; set; } 

    public virtual ICollection<SimpleEntityCollectionItem> SimpleCollection { get; set; } 
} 

public class SimpleEntityCollectionItem 
{ 
    public int Id { get; set; } 
    public int PropertyId { get; set; } 
} 

,我们有一些配置代码

AutoMapper.Mapper.CreateMap<SimpleModel, SimpleEntity>() 
      .ForMember(dest => dest.Id, src => src.Ignore()) 
      .ForMember(dest => dest.SimpleCollection, src => src.UseDestinationValue()); 

     AutoMapper.Mapper.CreateMap<SimpleModelCollectionItem, SimpleEntityCollectionItem>() 
      .ForMember(dest => dest.Id, src => src.Ignore()); 

     AutoMapper.Mapper.AssertConfigurationIsValid(); 

和测试数据初始化

  var model = new SimpleModel 
         { 
          PropertyId = 2, 
          SimpleCollection = 
           new List<SimpleModelCollectionItem> 
            { 
             new SimpleModelCollectionItem 
              { 
               PropertyId = 7 
              } 
            } 
         }; 
     var entity = new SimpleEntity 
         { 
          Id = 1, 
          PropertyId = 3, 
          SimpleCollection = 
           new List<SimpleEntityCollectionItem> 
            { 
             new SimpleEntityCollectionItem 
              { 
               Id = 5, 
               PropertyId = 4 
              } 
            } 
         }; 
     AutoMapper.Mapper.Map(model, entity); 

,我希望看到

Console.WriteLine(entity.Id); // 1 
Console.WriteLine(entity.PropertyId); // 2 
Console.WriteLine(entity.SimpleCollection.First().Id); // 5 but was 0 
Console.WriteLine(entity.SimpleCollection.First().PropertyId); // 7 

是否有可能内部收集的Id等于5,因为它最初是?

回答

1

因此,当AutoMapper映射您的集合时,它实际上会从目标集合中删除旧项目,然后添加一个新项目。

您可以通过使用此代码验证这一点:

var item_before = entity.SimpleCollection.First(); 

AutoMapper.Mapper.Map(model, entity); 

var item_after = entity.SimpleCollection.First(); 

bool item_same_references = object.ReferenceEquals(item_before, item_after); 

item_same_references值将是false

即使您使用的是src => src.UseDestinationValue(),也会发生这种情况。使用这只意味着它自己的集合对象应该被重用,但不是该集合中的项目。

我不确定是否有办法告诉AutoMapper也使用相同的收集项目。

另外,考虑一下,如果目标集合包含的源项目集合数量少于目标集合,会发生什么情况?

因此,您得到的零是因为当AutoMapper创建要添加到集合中的新项目时,Id属性的默认值为default(int),该值为零。

我建议如下:

我假设在源和目的地集合项目的数量是相等的。

首先,修改映射配置指示AutoMapper忽略这样的集合:

AutoMapper.Mapper.CreateMap<SimpleModel, SimpleEntity>() 
    .ForMember(dest => dest.Id, opt => opt.Ignore()) 
    .ForMember(dest => dest.SimpleCollection, opt => opt.Ignore()); 

然后,创建一个方法,这样,在地方收集的物品映射(不删除,然后添加新项目)像这样的:

public void MapCollectionsInPlace<TSource, TDestination>(IEnumerable<TSource> source_collection, 
    IEnumerable<TDestination> destination_collection) 
{ 
    var source_enumerator = source_collection.GetEnumerator(); 
    var destination_enumerator = destination_collection.GetEnumerator(); 

    while (source_enumerator.MoveNext()) 
    { 
     if(!destination_enumerator.MoveNext()) 
      throw new Exception("Source collection has more items than destination collection"); 

     AutoMapper.Mapper.Map(source_enumerator.Current, destination_enumerator.Current); 
    } 
} 

现在,你可以使用下面的代码:

AutoMapper.Mapper.Map(model, entity); 

MapCollectionsInPlace(model.SimpleCollection, entity.SimpleCollection);