简体   繁体   English

使用相同对象和不同TypeConverters的自动映射器进行双向映射

[英]Two way mapping with automapper using same objects and different TypeConverters

I want to use AutoMapper for mapping DTO s to Models. 我想使用AutoMapper将DTO映射到模型。 But my project contains some custom rules for default values for primitive types like [string null value is "_"], [default int value is -1] and [date time fields must be integer like 19990221] etc. 但是我的项目包含一些原始类型的默认值的自定义规则,例如[字符串null值为“ _”],[默认int值为-1]和[日期时间字段必须为整数,如19990221]等。

In my test i have a outer DTO which haves Null string values. 在我的测试中,我有一个外部DTO,它具有Null字符串值。 But my inner system model has a "null string must be represents as a "_" string" rule (its sucks but its a legacy design decision). 但是我的内部系统模型有一个“空字符串必须表示为“ _”字符串”规则(虽然很烂,但它是一个遗留的设计决策)。

Models: 楷模:

public class OuterDTO
{
    public string TestString { get; set; }
}

public class InnerModel
{
    public string TestString { get; set; }
}

Automapper type converters: 自动映射器类型转换器:

public class CustomStringToStringConverter : ITypeConverter<string, string>
{
    public string Convert(ResolutionContext context)
    {
        string source = (string)context.SourceValue;

        if (source == "_")
            return null;

        return source;
    }
}

public class StringToSafirStringConverter : ITypeConverter<string, string>
{
    public string Convert(ResolutionContext context)
    {
        string source = (string)context.SourceValue;

        if (source == null)
            return "_";

        return source;
    }
}

And my Test is : 我的测试是:

[TestMethod]
    public void StringToSafirStringConverterAndSafirStringToStringConverter_SafirDefaultNullStringAndNullString_ReturnsNullAndSafirNullString()
    {
        //Arrenge
        Mapper.CreateMap<string, string>().ConvertUsing(new StringToSafirStringConverter());//this has to used be DTO To Model map
        Mapper.CreateMap<string, string>().ConvertUsing(new SafirStringToStringConverter());//this has to used be Model To DTO map
        Mapper.CreateMap<InnerModel, OuterDTO>();
        Mapper.CreateMap<OuterDTO, InnerModel>();
        Mapper.AssertConfigurationIsValid();

        InnerModel expected1 = new InnerModel()
        {
            TestString = null
        };

        OuterDTO inner1 = new OuterDTO()
        {
            TestString = "_"
        };

        OuterDTO expected2 = new OuterDTO()
        {
            TestString = "_"
        };

        InnerModel outer1 = new InnerModel()
        {
            TestString = null
        };

        //Act
        InnerModel actual1 = Mapper.Map<OuterDTO, InnerModel>(inner1);
        OuterDTO actual2 = Mapper.Map<InnerModel, OuterDTO>(outer1);

        //Assert
        Assert.AreEqual(expected1.TestString, actual1.TestString);
        Assert.AreEqual(expected2.TestString, actual2.TestString);
    }

Second assert fails. 第二个断言失败。

I have to map DTO s to Models and Models to DTO s hundreds of cases and I have same issue in integer too. 我必须将DTO映射到Model,将Models映射到DTO的数百种情况,并且整数也存在相同的问题。 How can i choose converters to do different mappings? 如何选择转换器进行不同的映射?

You're declaring two mappings from string to string: 您要声明两个从字符串到字符串的映射:

Mapper.CreateMap<string, string>().ConvertUsing(new StringToSafirStringConverter());
Mapper.CreateMap<string, string>().ConvertUsing(new SafirStringToStringConverter());

Mappings cannot be overwritten, so if you look at the AutoMapper configuration you'll see just one mapping for string to string. 映射不能被覆盖,因此,如果您查看AutoMapper配置,您只会看到一个字符串到字符串的映射。 (Even if you could define two mappings for string to string, AutoMapper could not know which one to use.) (即使您可以为字符串到字符串定义两个映射,AutoMapper也无法知道要使用哪个映射。)

The way to do this is to define the mapping for the property using ValueResolvers: 完成此操作的方法是使用ValueResolvers定义属性的映射:

Mapper.CreateMap<InnerModel, OuterDTO>()
                .ForMember(dest => dest.TestString,
                    opt => opt.ResolveUsing<StringToSafirStringResolver>()
                       .FromMember(source => source.TestString));

Mapper.CreateMap<OuterDTO, InnerModel>()
                .ForMember(dest => dest.TestString,
                    opt => opt.ResolveUsing<SafirStringToStringResolver>()
                      .FromMember(source => source.TestString));

Then you write the ValueResolvers, say: 然后编写ValueResolvers,说:

public class StringToSafirStringResolver : ValueResolver<string, string>
{
    protected override string ResolveCore(string source)
    {
        return source ?? "_";
    }
}

public class SafirStringToStringResolver : ValueResolver<string, string>
{
    protected override string ResolveCore(string source)
    {
        return source == "_" ? null : source;
    }
}

You can then do the same thing for your int and datetime values. 然后,您可以对int和datetime值执行相同的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM