В случаях, когда мои целевые сеттеры являются закрытыми, я могу захотеть сопоставить объект с помощью конструктора целевого объекта. Как вы это сделаете с помощью Automapper?
Automapper - как сопоставлять параметры конструктора вместо свойств
Ответ 1
Используйте ConstructUsing
это позволит вам указать, какой конструктор использовать во время отображения. но тогда все остальные свойства будут автоматически сопоставлены в соответствии с соглашениями.
Также обратите внимание, что это отличается от ConvertUsing
тем, что использование преобразования не будет продолжать отображаться через соглашения, вместо этого оно даст вам полный контроль над отображением.
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
Вы должны использовать метод Map
, который позволяет вам установить пункт назначения. Например:
Mapper.CreateMap<ObjectFrom, ObjectTo>()
var from = new ObjectFrom { Name = "Jon", Age = 25 };
var to = Mapper.Map(from, new ObjectTo(param1));
Ответ 3
Лучшая практика - использовать документированные подходы от 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)));
Ответ 4
Во время написания этого ответа 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>();
}
}
Примечание. Предполагается, что вы используете профили для настройки сопоставлений вашего автомаппера.
При использовании, как показано ниже, это дает правильный объект:
var model = new PersonViewModel
{
Id = 1
Name = "John Smith"
}
// will correctly call the (id, name) constructor of Person
_mapper.Map<Person>(model);
Вы можете узнать больше о создании autopper в официальной вики на GitHub.