2013-11-20 2 views
3

Я использую AutoMapper для сопоставления между двумя коллекциями. Я вижу, что опция Ignore не работает в этом сценарии, как ожидалось. То, что я ожидаю, можно увидеть в методе AutoMapperIgnore_TwoObjectMappedWithIgnoreId_SameWithUnchangedIdAndNewPrice(). В других двух методах тестирования Id игнорируется, но каждый объект в коллекции создается снова с последствиями, которые будут потеряны исходные значения. Существует возможность использовать UseDestinationValue, но я думаю, что это имеет смысл только в классах, где коллекция является ее членом. Как использовать опцию Ignore в коллекциях?AutoMapper: сопоставление между двумя коллекциями с «Ignore»

[TestClass] 
public class AutoMapperTests 
{ 
    private readonly IEnumerable<Dto> _testDtos; 

    private readonly IEnumerable<Entity> _testEntities; 

    public AutoMapperTests() 
    { 
     _testDtos = new List<Dto> 
     { 
      new Dto() 
      { 
       Id = 0, 
       Fk_Id = 8, 
       Price = 350000 
      } 
     }; 


     _testEntities = new List<Entity> 
     { 
      new Entity() 
      { 
       Id = 8, 
       Price = 68000 
      } 
      , 
      new Entity() 
      { 
       Id = 6, 
       Price = 350000 
      } 
     }; 
    } 

    [TestInitialize] 
    public void TestInitialize() 
    { 
     Mapper.Reset(); 
    } 

    [TestMethod] 
    public void AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntityIgnoreId_SameWithUnchangedIdAndNewPrice() 
    { 
     //Assign 
     Mapper.CreateMap<Dto, Entity>() 
      .ForMember(destination => destination.Id, opt => opt.Ignore()); 

     AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntity_SameWithUnchangedIdAndNewPrice(true); 
    } 

    [TestMethod] 
    public void AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntityUseDestinationtValueForId_SameWithUnchangedIdAndNewPrice() 
    { 
     //Assign 
     Mapper.CreateMap<Dto, Entity>() 
      .ForMember(destination => destination.Id, opt => opt.UseDestinationValue()); 

     AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntity_SameWithUnchangedIdAndNewPrice(true); 
    } 


    private void AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntity_SameWithUnchangedIdAndNewPrice(bool isExceptedSame) 
    { 
     //Assign 
     var exceptedPrice = _testDtos.First().Price; 

     //Act 
     IEnumerable<Entity> foundEntities = _testEntities.Join(_testDtos, e => e.Id, e => e.Fk_Id, (entity, dto) => entity).ToList(); 
     Entity entityBeforeMapping = foundEntities.First(); 

     Mapper.Map(_testDtos, foundEntities); 

     Entity entityAfterMapping = foundEntities.First(); 


     //Assert 
     if (isExceptedSame) 
     { 
      Assert.AreSame(entityBeforeMapping, entityAfterMapping); 
     } 
     Assert.AreEqual(entityBeforeMapping.Id, entityAfterMapping.Id); 
     Assert.AreEqual(exceptedPrice, entityAfterMapping.Price); 
    } 

    [TestMethod] 
    public void AutoMapperIgnore_TwoObjectMappedWithIgnoreId_SameWithUnchangedIdAndNewPrice() 
    { 
     //Assign 
     Mapper.CreateMap<Dto, Entity>() 
      .ForMember(destination => destination.Id, opt => opt.Ignore()); 

     var testDto = new Dto() 
     { 
      Id = 0, 
      Fk_Id = 8, 
      Price = 350000 
     }; 

     var testEntity = new Entity() 
     { 
      Id = 8, 
      Price = 68000 
     }; 

     var exceptedPrice = testDto.Price; 


     //Act 
     Entity entityBeforeMapping = testEntity; 
     Mapper.Map(testDto, testEntity); 
     Entity entityAfterMapping = testEntity; 


     //Assert 
     Assert.AreSame(entityBeforeMapping, entityAfterMapping); 
     Assert.AreEqual(entityBeforeMapping.Id, entityAfterMapping.Id); 
     Assert.AreEqual(exceptedPrice, entityAfterMapping.Price); 
    } 

    internal class Dto 
    { 
     public int Id { get; set; } 
     public int Fk_Id { get; set; } 
     public Single? Price { get; set; } 
    } 

    internal class Entity 
    { 
     public int Id { get; set; } 
     public Single? Price { get; set; } 
    } 
} 

ответ

1

Как @Stef упоминался вы должны сопоставить каждую запись в сбор отдельно, как это

_testEntities.Join(_testDtos, e => e.Id, e => e.Fk_Id, (entity, dto) => Mapper.Map(dto,entity)); 

Здесь полный функциональный пример:

[TestClass] 
public class AutoMapperTests 
{ 
    private readonly IEnumerable<Dto> _testDtos; 

    private readonly IEnumerable<Entity> _testEntities; 

    public AutoMapperTests() 
    { 
     _testDtos = new List<Dto> 
     { 
      new Dto() 
      { 
       Id = 0, 
       Fk_Id = 8, 
       Price = 350000 
      } 
     }; 


     _testEntities = new List<Entity> 
     { 
      new Entity() 
      { 
       Id = 8, 
       Price = 68000 
      } 
      , 
      new Entity() 
      { 
       Id = 6, 
       Price = 350000 
      } 
     }; 
    } 

    [TestInitialize] 
    public void TestInitialize() 
    { 
     Mapper.Reset(); 
    } 

    [TestMethod] 
    public void AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntityIgnoreId_SameWithUnchangedIdAndNewPrice() 
    { 
     //Assign 
     Mapper.CreateMap<Dto, Entity>() 
      .ForMember(destination => destination.Id, opt => opt.Ignore()); 

     AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntity_SameWithUnchangedIdAndNewPrice(true); 
    } 

    [TestMethod] 
    public void AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntityUseDestinationtValueForId_SameWithUnchangedIdAndNewPrice() 
    { 
     //Assign 
     Mapper.CreateMap<Dto, Entity>() 
      .ForMember(destination => destination.Id, opt => opt.UseDestinationValue()); 


     AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntity_SameWithUnchangedIdAndNewPrice(true); 
    } 

    private void AutoMapperIgnore_TwoCollectionsWithOneCommonElementMappedFromDtoToEntity_SameWithUnchangedIdAndNewPrice(bool isExceptedSame) 
    { 
     //Assign 
     var exceptedPrice = _testDtos.First().Price; 

     //Act 
     Entity entityBeforeMapping = _testEntities.First(testEntity => testEntity.Id == _testEntities.First().Id); 
     IEnumerable<Entity> foundEntities = _testEntities.Join(_testDtos, e => e.Id, e => e.Fk_Id, (entity, dto) => Mapper.Map(dto,entity)); 
     Entity entityAfterMapping = foundEntities.First(); 


     //Assert 
     if (isExceptedSame) 
     { 
      Assert.AreSame(entityBeforeMapping, entityAfterMapping); 
     } 
     Assert.AreEqual(entityBeforeMapping.Id, entityAfterMapping.Id); 
     Assert.AreEqual(exceptedPrice, entityAfterMapping.Price); 
    } 

    [TestMethod] 
    public void AutoMapperIgnore_TwoObjectMappedWithIgnoreId_SameWithUnchangedIdAndNewPrice() 
    { 
     //Assign 
     Mapper.CreateMap<Dto, Entity>() 
      .ForMember(destination => destination.Id, opt => opt.Ignore()); 

     var testDto = new Dto() 
     { 
      Id = 0, 
      Fk_Id = 8, 
      Price = 350000 
     }; 

     var testEntity = new Entity() 
     { 
      Id = 8, 
      Price = 68000 
     }; 

     var exceptedPrice = testDto.Price; 


     //Act 
     Entity entityBeforeMapping = testEntity; 
     Mapper.Map(testDto, testEntity); 
     Entity entityAfterMapping = testEntity; 


     //Assert 
     Assert.AreSame(entityBeforeMapping, entityAfterMapping); 
     Assert.AreEqual(entityBeforeMapping.Id, entityAfterMapping.Id); 
     Assert.AreEqual(exceptedPrice, entityAfterMapping.Price); 
    } 

    internal class Dto 
    { 
     public int Id { get; set; } 
     public int Fk_Id { get; set; } 
     public Single? Price { get; set; } 
    } 

    internal class Entity 
    { 
     public int Id { get; set; } 
     public Single? Price { get; set; } 
    } 
} 
0

Я сделал несколько тестов и подтвердил вашу проблему.

Когда отображается список IEnumerable, AutoMapper создает новый список IEnumerable, который включает только свойства, которые вы определяете для сопоставления, так что только «Цена».

Чтобы сопоставить Dto с Entity, вам необходимо определить свойство, которое делает их уникальными, например PrimaryKey.

class Dto 
{ 
    public long PrimaryKey { get; set; } 
    public int Id { get; set; } 
    public int Fk_Id { get; set; } 
    public Single? Price { get; set; } 
} 

class Entity 
{ 
    public long PrimaryKey { get; set; } 
    public int Id { get; set; } 

    public Single? Price { get; set; } 
} 

Отображение списка в список можно сделать так:

// Update entities in original list 
foreach (var d in _testDtos) 
{ 
    foreach (var e in _testEntities) 
    { 
     if (e.PrimaryKey == d.PrimaryKey) 
     { 
      Mapper.Map(d, e); 
     } 
    } 
} 

Или больше LINQ дружественным:

// Create a new list 
var foundEntities = _testEntities.Join(_testDtos, e => e.PrimaryKey, d => d.PrimaryKey, (entity, dto) => Mapper.Map<Entity>(dto)).ToList(); 
+1

Thx для информации, но это кажется ошибкой, потому что обычно не требуется создавать дополнительное сопоставление для коллекций! –

+1

Я добавлю вопрос о github для этого, давайте посмотрим, поможет ли нам Джимми. –

+0

@Steff: THX. Не могли бы вы разместить ссылку на эту проблему здесь! BTW: Я нашел очень похожую проблему (даже если проблема не имеет ничего общего с коллекциями). https://github.com/AutoMapper/AutoMapper/issues/319 –

Смежные вопросы