从DataRow到DTO的映射,每个目标成员具有多个可能的列

时间:2019-02-26 11:38:39

标签: c# automapper

我正在尝试创建一个AutoMapper配置文件,该配置文件允许将Dictionary<string, string>映射到我的DTO,其中每个目标属性或路径都可以在零列或更多列中找到。为了简化下面的复制过程,我使用了DataRow而不是xunit

使用以下类从NuGet的automapperpublic 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; } } 开始使用新的.NET Core类库:

[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. ; } } 表达式中相当脆弱的代码:

<div class="page-box">
      <h1 class="page-title">用户登录</h1>

      <form action="user_login_check.php" method="post" id="form_login" onsubmit="send_form('form_login');return false;"> 

      <div id="form_login_notice" class="alert alert-warning" style="display: none;" ></div>

      <div class="form-group">
        <input type="text" name="email" placeholder="Email" class="form-control" />
      </div>
      <div class="form-group">
        <input type="password" name="password" placeholder="密码(6-12个字符)" class="form-control" />
      </div>
      <div class="form-group">
        <input type="submit"  value="登录" class="btn btn-primary" />
      </div>
      </form>

    </div>

我考虑过this answer with a custom resolver,但是看不到如何通过可能的源名称列表,,我看不到如何优化这种方法来通过第二次测试

可能我正在尝试使用错误的工具来完成这项工作,而我不应该尝试强迫AutoMapper为我这样做吗?还是有我看不到的选项?

0 个答案:

没有答案