我想使用AutoMapper将DTO映射到模型。但我的项目包含一些原始类型默认值的自定义规则,如[string null value is“_”],[default int value is -1]和[date time fields必须是整数,如19990221]等。
在我的测试中,我有一个外部DTO,它具有Null字符串值。但我的内部系统模型有一个“空字符串必须表示为”_“字符串”规则(它很糟糕,但它是一个传统的设计决定)。
型号:
public class OuterDTO
{
public string TestString { get; set; }
}
public class InnerModel
{
public string TestString { get; set; }
}
Automapper类型转换器:
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;
}
}
我的测试是:
[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);
}
第二个断言失败。
我必须将DTO映射到模型和模型到DTO的数百个案例,我也有整数相同的问题。如何选择转换器进行不同的映射?
答案 0 :(得分:1)
您正在声明从字符串到字符串的两个映射:
Mapper.CreateMap<string, string>().ConvertUsing(new StringToSafirStringConverter());
Mapper.CreateMap<string, string>().ConvertUsing(new SafirStringToStringConverter());
映射不能被覆盖,因此如果查看AutoMapper配置,您将只看到一个字符串到字符串的映射。 (即使您可以为字符串定义两个映射到字符串,AutoMapper也无法知道要使用哪个映射。)
执行此操作的方法是使用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));
然后你写了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;
}
}
然后,您可以为int和datetime值执行相同的操作。