【问题标题】:AutoMapper: Mapping between the two collections with 'Ignore'AutoMapper:使用“忽略”在两个集合之间进行映射
【发布时间】:2013-11-25 23:33:23
【问题描述】:

我正在使用 AutoMapper 在两个集合之间进行映射。我看到的是选项Ignore 在这种情况下没有按预期工作。我所期待的可以在方法AutoMapperIgnore_TwoObjectMappedWithIgnoreId_SameWithUnchangedIdAndNewPrice() 中看到。在其他两种测试方法中,Id 虽然被忽略了,但集合中的每个对象都会再次创建,其后果是原始值将丢失。有可能使用UseDestinationValue,但我认为这只对集合是它的成员的类有意义。如何在集合上使用选项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; }
    }
}

【问题讨论】:

    标签: c# .net collections automapper


    【解决方案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; }
        }
    }
    

    【讨论】:

      【解决方案2】:

      我做了一些测试并确认了您的问题。

      当一个 IEnumerable 列表被映射时,AutoMapper 会创建一个新的 IEnumerable 列表,它只包含您定义要映射的属性,因此只有“价格”。

      为了将 Dto 映射到实体,您需要定义一个属性,使它们成为唯一的,例如 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();
      

      【讨论】:

      • 感谢信息,但这似乎是一个错误,因为通常不需要为集合创建额外的映射!
      • 我会在github上添加一个问题,让我们看看Jimmy是否可以帮助我们。
      • @Steff:谢谢。您能否在此处发布问题的链接!顺便说一句:我发现了一个非常相似的问题(即使该问题与集合无关)。 github.com/AutoMapper/AutoMapper/issues/319
      • @Stef 感谢您的提示,但是当我为 IEnumerables 属性创建 Map 时,根本没有映射
      • @AntonKalcik ;您需要设置两个映射。 IEnunemrable 的原件和这张地图。
      猜你喜欢
      • 1970-01-01
      • 2012-07-01
      • 2011-06-26
      • 2017-02-14
      • 2015-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多