2015-10-17 5 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 

Это возможно set 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);