代码之家  ›  专栏  ›  技术社区  ›  jlembke

如何映射到构造函数参数而不是属性设置器

  •  90
  • jlembke  · 技术社区  · 15 年前

    4 回复  |  直到 5 年前
        1
  •  157
  •   Pavel Jounda Tom Hall    6 年前

    使用 ConstructUsing

    这将允许您指定在映射期间使用哪个构造函数。但是所有其他属性都将根据约定自动映射。

    还要注意,这与 ConvertUsing 在这种情况下,convert-using将不会继续通过约定进行映射,而是让您完全控制映射。

    Mapper.CreateMap<ObjectFrom, ObjectTo>()
        .ConstructUsing(x => new ObjectTo(arg0, arg1, etc));
    

    using AutoMapper;
    using NUnit.Framework;
    
    namespace UnitTests
    {
        [TestFixture]
        public class Tester
        {
            [Test]
            public void Test_ConstructUsing()
            {
                Mapper.CreateMap<ObjectFrom, ObjectTo>()
                    .ConstructUsing(x => new ObjectTo(x.Name));
    
                var from = new ObjectFrom { Name = "Jon", Age = 25 };
    
                ObjectTo to = Mapper.Map<ObjectFrom, ObjectTo>(from);
    
                Assert.That(to.Name, Is.EqualTo(from.Name));
                Assert.That(to.Age, Is.EqualTo(from.Age));
            }
        }
    
        public class ObjectFrom
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    
        public class ObjectTo
        {
            private readonly string _name;
    
            public ObjectTo(string name)
            {
                _name = name;
            }
    
            public string Name
            {
                get { return _name; }
            }
    
            public int Age { get; set; }
        }
    }
    
        2
  •  14
  •   d219    5 年前

    最佳实践是使用AutoMapper提供的有文档记录的方法 http://docs.automapper.org/en/stable/Construction.html

    public class SourceDto
    {
            public SourceDto(int valueParamSomeOtherName)
            {
                Value = valueParamSomeOtherName;
            }
    
            public int Value { get; }
    }
    
    Mapper.Initialize(cfg => cfg.CreateMap<Source, SourceDto>().ForCtorParam("valueParamSomeOtherName", opt => opt.MapFrom(src => src.Value)));
    
        3
  •  12
  •   Pavel Jounda Tom Hall    6 年前

    你应该使用 Map

    Mapper.CreateMap<ObjectFrom, ObjectTo>()
    
    var from = new ObjectFrom { Name = "Jon", Age = 25 };
    
    var to = Mapper.Map(from, new ObjectTo(param1));
    
        4
  •  5
  •   lxalln    5 年前

    在写这个答案的时候,AutoMapper会自动完成(用一个简单的 CreateMap<>() .ConstructUsing(...) 是一条路要走。

    public class PersonViewModel
    {
        public int Id { get; set; }
    
        public string Name { get; set; }
    }
    
    public class Person
    {
        public Person (int id, string name)
        {
            Id = id;
            Name = name;
        }
    
        public int Id { get; }
    
        public string Name { get; }
    }
    
    public class PersonProfile : Profile
    {
        public PersonProfile()
        {
            CreateMap<PersonViewModel, Person>();
        }
    }
    

    注意:这假设您正在使用 Profiles

    如下所示使用时,将生成正确的对象:

    var model = new PersonViewModel
    {
        Id = 1
        Name = "John Smith"
    }
    
    // will correctly call the (id, name) constructor of Person
    _mapper.Map<Person>(model);
    

    wiki on GitHub

        5
  •  3
  •   Jérôme MEVEL    4 年前

    就我个人而言,在使用AutoMapper时,我总是希望尽可能明确,以避免将来出现任何潜在的错误。

    如果你打电话给 ConstructUsing

    如果开发人员反转2个字符串参数或在一些现有可选参数之前添加一个新的可选参数,该怎么办?如果某个属性没有映射到它应该映射的目标属性,则会出现映射错误。

    这是不同的签名 施工 方法:

    TMappingExpression ConstructUsing(Func<TSource, ResolutionContext, TDestination> ctor);
    TMappingExpression ConstructUsing(Expression<Func<TSource, TDestination>> ctor);
    

    an expression tree may not contain a named argument specification ).

     CreateMap<FromType, ToType>()
        .ConstructUsing((src, res) =>
        {
            return new ToType(
                foo: src.MyFoo,
                bar: res.Mapper.Map<BarModel>(src.MyBar),
            );
        });
    

    注意Func的第二个参数 res Resolution Context . 此参数允许您使用已注册的映射。

    private set Map 方法:

    TDestination Map<TSource, TDestination>(TSource source, TDestination destination);
    

    mapper.Map(updateModel, existingEntity);
    await dbContext.SaveChangesAsync();
    

    谢天谢地还有 another way to update entities with EF Core .