Отображение из DataRow в DTO с несколькими возможными столбцами на элемент назначения - PullRequest
0 голосов
/ 26 февраля 2019

Я пытаюсь создать профиль 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 сделать это для меня?Или есть вариант, которого я не вижу?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...