如何正确配置int?'到' int '投影使用AutoMapper
本文关键字:int AutoMapper 投影 何正确 配置 | 更新日期: 2023-09-27 18:12:44
我有一些麻烦,让这个正确工作。我有两个类:
public class TestClassA
{
public int? NullableIntProperty { get; set; }
}
public class TestClassB
{
public int NotNullableIntProperty { get; set; }
}
然后设置以下映射:
cfg.CreateMap<TestClassA, TestClassB>()
.ForMember(dest => dest.NotNullableIntProperty,
opt => opt.MapFrom(src => src.NullableIntProperty));
cfg.CreateMap<TestClassA, TestClassA>()
.ForMember(dest => dest.NullableIntProperty,
opt => opt.MapFrom(src => src.NullableIntProperty));
cfg.CreateMap<TestClassB, TestClassA>()
.ForMember(dest => dest.NullableIntProperty,
opt => opt.MapFrom(src => src.NotNullableIntProperty));
cfg.CreateMap<TestClassB, TestClassB>()
.ForMember(dest => dest.NotNullableIntProperty,
opt => opt.MapFrom(src => src.NotNullableIntProperty));
我现在设置了四个映射,并将测试以下场景:
int? => int
int => int?
int => int
int? => int?
在测试类中,我像这样使用映射:var testQueryableDest = testQueryableSrc.ProjectTo<...>(_mapper.ConfigurationProvider);
我希望在这个阶段不工作的唯一投影是TestClassA => TestClassB
,因为我可以看到AutoMapper可能不知道在值为null
的情况下如何处理int?
。果然,事实就是如此。因此,我为int? => int
设置了如下映射:
cfg.CreateMap<int?, int>()
.ProjectUsing(src => src ?? default(int));
这就是事情变得奇怪的地方。当我添加这个映射时,TestClassB => TestClassB
的映射甚至无法创建。它给出如下错误信息:
System类型的表达式。Int32'不能用于赋值类型'System.Nullable ' 1[System.Int32]'
我发现这条消息非常奇怪,因为TestClassB
上根本没有int?
。这是怎么回事?我觉得我一定是误解了AutoMapper需要如何处理这些投影。我意识到各种代码可能很难拼凑在一起,所以这里是整个测试类供参考:
[TestClass]
public class BasicTests
{
private readonly IMapper _mapper;
public BasicTests()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<int?, int>()
.ProjectUsing(src => src ?? default(int));
cfg.CreateMap<TestClassA, TestClassB>()
.ForMember(dest => dest.IntProperty, opt => opt.MapFrom(src => src.NullableIntProperty));
cfg.CreateMap<TestClassA, TestClassA>()
.ForMember(dest => dest.NullableIntProperty, opt => opt.MapFrom(src => src.NullableIntProperty));
cfg.CreateMap<TestClassB, TestClassA>()
.ForMember(dest => dest.NullableIntProperty, opt => opt.MapFrom(src => src.IntProperty));
cfg.CreateMap<TestClassB, TestClassB>()
.ForMember(dest => dest.IntProperty, opt => opt.MapFrom(src => src.IntProperty));
});
_mapper = new Mapper(config);
}
[TestMethod]
public void CanMapNullableIntToInt()
{
var testQueryableSource = new List<TestClassA>
{
new TestClassA
{
NullableIntProperty = null
}
}.AsQueryable();
var testQueryableDestination = testQueryableSource.ProjectTo<TestClassB>(_mapper.ConfigurationProvider);
}
[TestMethod]
public void CanMapNullableIntToNullableInt()
{
var testQueryableSource = new List<TestClassA>
{
new TestClassA
{
NullableIntProperty = null
}
}.AsQueryable();
var testQueryableDestination = testQueryableSource.ProjectTo<TestClassA>(_mapper.ConfigurationProvider);
}
[TestMethod]
public void CanMapIntToNullableInt()
{
var testQueryableSource = new List<TestClassB>
{
new TestClassB
{
IntProperty = 0
}
}.AsQueryable();
var testQueryableDestination = testQueryableSource.ProjectTo<TestClassA>(_mapper.ConfigurationProvider);
}
[TestMethod]
public void CanMapIntToInt()
{
var testQueryableSource = new List<TestClassB>
{
new TestClassB
{
IntProperty = 0
}
}.AsQueryable();
var testQueryableDestination = testQueryableSource.ProjectTo<TestClassB>(_mapper.ConfigurationProvider);
}
}
我发现复制这种情况的最短方法如下:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<int?, int>().ProjectUsing(x => x ?? default(int));
cfg.CreateMap<TestClassA, TestClassA>()
.ForMember(a => a.NullableIntPropety, o => o.MapFrom(a => a.NullableIntProperty));
}
在我看来,AutoMapper试图在这里使用int? => int
映射器,尽管更明显的基于身份的映射将在这里使用。
因为每个int
也是一个有效的int?
,所以AutoMapper 尝试在这里使用int? => int
映射器并将结果赋值给int?
成员。但是,在解析该赋值时,似乎在底层有些东西没有正确工作,因此出现了异常。
似乎修复它是添加另一个映射,int? => int?
的身份映射:
cfg.CreateMap<int?, int?>().ProjectUsing(x => x);
然后,这个映射被使用,并且没有异常发生(并且映射也正确地工作-与您的所有示例)。
这个问题似乎存在于当前的AutoMapper 5.1。X版本(当前是5.1.1)。好消息是,这个问题已经被解决了。如果您从myget提要中尝试当前的5.2 alpha版本,那么代码可以正常工作,没有任何问题。
自5.1.1发布以来,代码库已经看到了相当多的贡献,对可空映射进行了多个修复(例如这个和这个拉请求)。我想其中一个修改已经解决了这个问题。最有可能的是,它是pull request #1672,这只是意味着删除不需要的代码,但显然也修复了问题1664,这是关于AutoMapper显然优先于非空源映射的可空源映射,即使一个非空源被映射。这听起来很像你所遇到的问题。
所以,现在,你可以添加上面的解决方法来将类型映射到自身或使用alpha版本,而我们等待5.2发布。