Я пытаюсь создать профиль AutoMapper, который позволяет сопоставить DataRow
с моим DTO, где каждое свойство или путь назначения может быть найдено в ноль или более столбцов .Чтобы упростить мое воспроизведение ниже, я использую Dictionary<string, string>
вместо DataRow
.
Начните с новой библиотеки классов .NET Core, используя xunit
и automapper
из NuGet, используя следующие классы:
public class Person
{
public string Name { get; set; }
}
// Simplified for repro, in reality this is a DataRow in a DataTable
public class Data
{
public IDictionary<string, string> Values { get; set; }
}
Затем я пытаюсь выполнить хотя бы следующие юнит-тесты:
[Theory]
[InlineData("name")]
[InlineData("Full name")]
public void Can_find_mapped_column(string columnName)
{
var person = new Person { Name = "John" };
var data = new Data { Values = new Dictionary<string, string> { { columnName, "Johnnie" } } };
var mapper = new MapperConfiguration(c => c.AddProfile(new MyProfile())).CreateMapper();
person = mapper.Map<Data, Person>(data, person);
Assert.Equal("Johnnie", person.Name);
}
[Fact]
public void Can_skip_property()
{
var person = new Person { Name = "John" };
var data = new Data { Values = new Dictionary<string, string> { { "Irrelevant Column", "foobar" } } };
var mapper = new MapperConfiguration(c => c.AddProfile(new MyProfile())).CreateMapper();
person = mapper.Map<Data, Person>(data, person);
Assert.Equal("John", person.Name);
}
Я пробовал этот профиль, но он не работает:
public class MyProfile : Profile
{
public MyProfile()
{
CreateMap<Data, Person>()
.ForMember(p => p.Name, o =>
{
o.PreCondition(d => d.Values.ContainsKey("name"));
o.MapFrom(d => d.Values["name"]);
})
.ForMember(p => p.Name, o =>
{
o.PreCondition(d => d.Values.ContainsKey("Full name"));
o.MapFrom(d => d.Values["Full name"]);
})
// Etc.
;
}
}
Я нашел обходной путь, но он требует довольно хрупкого кода в выражении MapFrom
:
public class MyProfile : Profile
{
public MyProfile()
{
CreateMap<Data, Person>()
.ForMember(p => p.Name, o =>
{
var names = new[] { "name", "Full name", };
o.PreCondition(d => names.Any(n => d.Values.ContainsKey(n)));
o.MapFrom(d => names.Aggregate((string)null, (result, next) => result != null || !d.Values.ContainsKey(next) ? result : d.Values[next]));
})
// Etc.
;
}
}
Я рассмотрел этот ответ с пользовательским распознавателем , но не смог понять, как я могу передатьсписок возможных имен источников, и Я не понимаю, как я могу усовершенствовать этот подход, чтобы выполнить мой второй тест.
Возможно, я пытаюсь использовать неправильный инструмент дляработа, и я не должен пытаться заставить AutoMapper сделать это для меня?Или есть вариант, которого я не вижу?