C# 使用相同对象和不同类型转换器的automapper双向映射

C# 使用相同对象和不同类型转换器的automapper双向映射,c#,automapper,automapper-2,automapper-3,C#,Automapper,Automapper 2,Automapper 3,我想使用AutoMapper将DTO映射到模型。但是我的项目包含一些基本类型的默认值的自定义规则,如[string null value是“”]、[default int value是-1]和[date time fields必须是整数,如19990221]等 在我的测试中,我有一个外部DTO,它有空字符串值。但我的内部系统模型有一个“空字符串必须表示为”u“字符串”规则(它很糟糕,但它是一个遗留的设计决策) 型号: public class OuterDTO { public stri

我想使用AutoMapper将DTO映射到模型。但是我的项目包含一些基本类型的默认值的自定义规则,如[string null value是“”]、[default int value是-1]和[date time fields必须是整数,如19990221]等

在我的测试中,我有一个外部DTO,它有空字符串值。但我的内部系统模型有一个“空字符串必须表示为”u“字符串”规则(它很糟糕,但它是一个遗留的设计决策)

型号:

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;
    }
}
公共类CustomStringToStringConverter:ITypeConverter
{
公共字符串转换(ResolutionContext上下文)
{
字符串源=(字符串)context.SourceValue;
如果(源==“389;”)
返回null;
返回源;
}
}
公共类StringToSafirStringConverter:ITypeConverter
{
公共字符串转换(ResolutionContext上下文)
{
字符串源=(字符串)context.SourceValue;
if(source==null)
返回“\”;
返回源;
}
}
我的测试是:

[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);
    }
[TestMethod]
public void StringToSafirStringConverter和SafirStringToStringConverter\u SafirDefaultNullStringAndNullString\u returnsAllandSafirNullString()
{
//拖欠
Mapper.CreateMap().ConvertUsing(新的StringToSafirStringConverter());//必须使用DTO进行模型映射
Mapper.CreateMap().ConvertUsing(新的SafirStringToStringConverter());//必须使用模型到数据进行映射
CreateMap();
CreateMap();
assertConfigurationsValid();
InnerModel expected1=新的InnerModel()
{
TestString=null
};
OuterDTO inner1=新的OuterDTO()
{
TestString=“\u0”
};
OuterDTO expected2=新的OuterDTO()
{
TestString=“\u0”
};
InnerModel outer1=新的InnerModel()
{
TestString=null
};
//表演
InnerModel actual1=Mapper.Map(inner1);
OuterDTO actual2=Mapper.Map(outer1);
//断言
AreEqual(expected1.TestString,actual1.TestString);
AreEqual(expected2.TestString,actual2.TestString);
}
第二个断言失败


我必须将DTO映射到模型,并将模型映射到DTO数百个案例,在integer中我也有同样的问题。如何选择转换器来执行不同的映射?

您正在声明两个从字符串到字符串的映射:

Mapper.CreateMap<string, string>().ConvertUsing(new StringToSafirStringConverter());
Mapper.CreateMap<string, string>().ConvertUsing(new SafirStringToStringConverter());
Mapper.CreateMap().ConvertUsing(新的StringToSafirStringConverter());
CreateMap().ConvertUsing(新的SafirStringToStringConverter());
映射不能被覆盖,因此如果您查看AutoMapper配置,您将只看到一个字符串到字符串的映射。(即使您可以为字符串到字符串定义两个映射,AutoMapper也不知道要使用哪个映射。)

执行此操作的方法是使用ValueResolver定义属性的映射:

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));
Mapper.CreateMap()
.FormMember(dest=>dest.TestString,
opt=>opt.resolvesusing()
.FromMember(source=>source.TestString));
Mapper.CreateMap()
.FormMember(dest=>dest.TestString,
opt=>opt.resolvesusing()
.FromMember(source=>source.TestString));
然后写下ValueResolver,比如:

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;
    }
}
公共类StringToSafirStringResolver:ValueResolver
{
受保护的重写字符串解析核心(字符串源)
{
返回源??“\”;
}
}
公共类SafirStringToStringResolver:ValueResolver
{
受保护的重写字符串解析核心(字符串源)
{
返回源==“?”,空:源;
}
}

然后,您可以对int和datetime值执行相同的操作。

这是实际的操作方法,但我正在尝试摆脱映射问题。我有200个模型和数千个字段。也许我必须找到一种处理ValueResolver的方法。如果您所有的string、int和datetime字段都有这些默认值,那么您可能可以使用反射为您生成映射。