Automapper版本:6.0.2
我有两个类InternalEntity
作为我的数据源,PublicEntity
作为API公开。我尝试使用InternalEntity
方法通过PublicEntity
投影访问UseAsDataSource
。
问题是内部bool
属性映射到公共Nullable<bool>
属性。
当我在投影中使用此属性时失败,例如在那上面调用OrderBy。有关详细信息,请参阅下面的示例。
我可以为bool设置投影规则吗? - &GT; bool不知何故?
以下是代码示例:
using AutoMapper;
using AutoMapper.QueryableExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Sample
{
internal class Program
{
public class PublicEntity
{
public string PublicName { get; set; }
public bool? Active { get; set; }
}
public class InternalEntity
{
public string InternalName { get; set; }
public bool Active { get; set; }
}
private static IMapper mapper;
private static void SetupMapping()
{
var mc = new MapperConfiguration(cfg =>
{
cfg.CreateMap<InternalEntity, PublicEntity>()
.ForMember(dest => dest.PublicName, opt => opt.MapFrom(src => src.InternalName));
// setup bool? -> bool projection somehow
});
mc.AssertConfigurationIsValid();
mapper = mc.CreateMapper();
}
private static void Main(string[] args)
{
SetupMapping();
try
{
IQueryable<PublicEntity> resultable = DataSource()
.UseAsDataSource(mapper)
.For<PublicEntity>()
.OrderBy(x => x.Active);
resultable.ToList()
.ForEach(x => Console.WriteLine(x.PublicName));
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadLine();
}
private static IQueryable<InternalEntity> DataSource()
{
return new List<InternalEntity>()
{
new InternalEntity(){ InternalName = "Name 1", Active = true},
new InternalEntity(){ InternalName = "Name 3", Active = true},
new InternalEntity(){ InternalName = "Name 2", Active = false},
}.AsQueryable();
}
}
}
例外:
System.ArgumentException: Expression of type 'System.Linq.Expressions.Expression`1[System.Func`2[Sample.Program+InternalEntity,System.Boolean]]' cannot be used for parameter of type 'System.Linq.Expressions.Expression`1[System.Func`2[Sample.Program+InternalEntity,System.Nullable`1[System.Boolean]]]' of method 'System.Linq.IOrderedQueryable`1[Sample.Program+InternalEntity] OrderBy[InternalEntity,Nullable`1](System.Linq.IQueryable`1[Sample.Program+InternalEntity], System.Linq.Expressions.Expression`1[System.Func`2[Sample.Program+InternalEntity,System.Nullable`1[System.Boolean]]])'
at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
at AutoMapper.Mappers.ExpressionMapper.MappingVisitor.GetConvertedMethodCall(MethodCallExpression node)
at AutoMapper.Mappers.ExpressionMapper.MappingVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at AutoMapper.QueryableExtensions.Impl.SourceInjectedQueryProvider`2.ConvertDestinationExpressionToSourceExpression(Expression expression)
at AutoMapper.QueryableExtensions.Impl.SourceInjectedQueryProvider`2.Execute[TResult](Expression expression)
at AutoMapper.QueryableExtensions.Impl.SourceSourceInjectedQuery`2.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Sample.Program.Main(String[] args) in xxxx\Program.cs:line 48
答案 0 :(得分:3)
我自己找到了解决方案。一条或另一条线路做得很好:
.ForMember(dest => dest.Active, opt => opt.MapFrom(src => (bool?)src.Active))
.ForMember(dest => dest.Active, opt => opt.MapFrom(src => new Nullable<bool>(src.Active)))
这些行在语义上是等效的。
请注意,这些行会生成不同的表达式树,如果要解析表达式树,这些树可能会变得很重要。
答案 1 :(得分:2)
这个错误听起来合乎逻辑 - 你试图转换一个可以容纳&#34; true&#34;,&#34; false&#34;或者&#34;没有价值&#34;另一个只能持有&#34; true&#34;或&#34;假&#34;。
您可以告诉它从可空Value
:
var mc = new MapperConfiguration(cfg =>
{
cfg.CreateMap<InternalEntity, PublicEntity>()
.ForMember(dest => dest.PublicName, opt => opt.MapFrom(src => src.InternalName))
.ForMember(dest => dest.Active, opt => opt.MapFrom(src => src.Active.Value));
});
请注意,如果源Active
没有值(显然),它将抛出异常。
如果Active
等于null
表示&#34;无效&#34;,那么您只需使用??
运算符:
.ForMember(dest => dest.Active, opt => opt.MapFrom(src => src.Active.Value ?? false));
但是为什么你需要一个可以为空的呢? :)