在我的项目中,我有一个Linq可查询(实际上是一个EF6集合),我需要将其转换为数据传输对象的集合。我在整个项目中使用AutoMapper
,特别是因为它能够进行类型投影,从而减少了Linq查询生成的SQL数量。
但是我的一个DTO课程遇到了一个小问题。关联的数据库列包含一个可以为空的字符串,我希望将其映射到可以为空的枚举。但是在运行时会抛出异常
没有强迫操作者类型 'System.String' 之间限定和 'System.Nullable`1 [AutomapperEnumTest.Method]'。
这是一个完整的测试程序,用于演示问题:(请参阅.Net Fiddle)
using System;
using System.Linq;
using AutoMapper;
using AutoMapper.QueryableExtensions;
namespace AutomapperEnumTest
{
public class Program
{
public static void Main()
{
Configure();
var src = new SourceType[] { new SourceType { Name = "Rob", MethodName = "AUTO" } };
var results = src.AsQueryable()
.ProjectTo<DestType>();
foreach(var item in results)
{
Console.WriteLine(String.Format("DestType Name={0} Method={1}", item.Name, item.Method));
}
Console.WriteLine("Done");
}
private static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<string, Method?>().ProjectUsing(src => src == "MANUAL" ? Method.MANUAL : Method.AUTO);
cfg.CreateMap<SourceType, DestType>()
.ForMember(dest => dest.Method, opt => opt.MapFrom(src => src.MethodName));
});
}
}
public enum Method
{
MANUAL=0,
AUTO=1
}
public class DestType
{
public string Name {get; set; }
public Method? Method {get; set; }
}
public class SourceType
{
public string Name {get; set; }
public string MethodName {get; set; }
}
}
现在,如果我将属性从Method?
更改为Method
,则可以正常工作(请参阅.Net Fiddle中的此修改)。但是我不想这样做,所以我的问题是如何通知Linq / AutoMapper它应该使用我的ProjectUsing
作为可以为空的枚举?
非常感谢。
答案 0 :(得分:1)
您可以手动将MethodName映射到Method,除非我在您的问题中遗漏了某些内容。
private static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<SourceType, DestType>()
.ForMember(dest => dest.Method, opt => opt.MapFrom(src =>
src.MethodName == "MANUAL" ? Method.MANUAL : Method.AUTO));
});
}
答案 1 :(得分:1)
最新的AutoMapper v5.2.0也是如此。
在查看源代码之后,我认为这是ExpressionBuilder
类中的一个错误,因为由于某些未知原因,NullableExpressionBinder
的优先级高于CustomProjectionExpressionBinder
(和其他),所以基本上,当您将非可空类型映射为可空时,将忽略所有自定义映射。
我建议你在他们的存储库上报告。在那之前,我可以建议你以下的解决方法(hack)。在项目中包含以下自定义类:
using System.Linq.Expressions;
using System.Reflection;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using AutoMapper.QueryableExtensions.Impl;
class NullableExpressionBinderEx : IExpressionBinder
{
public static void Install()
{
var bindersField = typeof(ExpressionBuilder).GetField("Binders", BindingFlags.NonPublic | BindingFlags.Static);
var binders = (IExpressionBinder[])bindersField.GetValue(null);
binders[0] = new NullableExpressionBinderEx();
}
IExpressionBinder baseBinder = new NullableExpressionBinder();
private NullableExpressionBinderEx() { }
public bool IsMatch(PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionResolutionResult result)
{
if (propertyTypeMap != null && propertyTypeMap.CustomProjection != null)
return false;
return baseBinder.IsMatch(propertyMap, propertyTypeMap, result);
}
public MemberAssignment Build(IConfigurationProvider configuration, PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionRequest request, ExpressionResolutionResult result, IDictionary<ExpressionRequest, int> typePairCount)
{
return baseBinder.Build(configuration, propertyMap, propertyTypeMap, request, result, typePairCount);
}
}
然后将以下行添加到您的Configure
方法中:
NullableExpressionBinderEx.Install();
问题应该解决。