AutoMapper IQueryable 扩展的
Project().To<TViewModel>().SingleOrDefault()
抛出此异常:
无法比较“App.Domain.MyComplexType”类型的元素。只有原始类型, 支持枚举类型和实体类型。
我有这个型号:
public class MyEntityType // this is an entity type on the dbContext
{
public int Id {get;set;
public MyComplexType MyComplexType {get;set;}
}
public class MyComplexType // this is a complex type
{
public decimal Property1 { get; set;}
public string Property2 { get;set;}
}
public class ViewModel
{
public int Id { get;set;}
public decimal MyComplexTypeProperty1 { get;set;}
}
我使用 AutoMapper 配置从
IQueryable<MyEntityType>
到 ViewModel
的映射:
Mapper.CreateMap<MyEntityType, MyComplexType>(); // I rely on AutoMapper's
//convention for flattening `source.MyComplexType.Property1` to `dest.MyComplexTypeProperty1'
然后我尝试检索这样的单个项目:
var myItem = myContext.Where(x => x.Id == id).Project().To<ViewModel>().SingleOrDefault();
当调用
SingleOrDefault()
时,我得到了上述异常,所以显然
我目前通过首先调用
SingleOrDefault()
然后进行映射来解决此问题,这有效:
var myItem = Mapper.Map<ViewModel>(myContext.Find(id));
其他帖子基本上说,当尝试将 EF 复杂类型与 null 进行比较时,例如在
Where
子句中,会出现上述错误,但这里显然不是这种情况。
LINQ toEntity 无法按照您的建议对复杂类型执行比较(空检查)。例如,这不起作用...
myContext.Select(i => new
{
MyComplexType = i.MyComplexType != null ?
new MyComplexTypeViewModel()
{
Property1 = i.MyComplexType.Property1
}
: null
})
默认情况下,Automapper 尝试将 null 源值映射为 null,有时在使用
Project().To<>()
或 Mapper.Engine.CreateMapExpression<,>()
时在生成的表达式中添加类似的条件。
在我的例子中,我将整个复杂类型映射到它自己的视图模型,并且没有使用属性扁平化。这个配置值解决了我的问题...
Mapper.AllowNullDestinationValues = false;
您可以尝试使用
CreateMapExpression<TSource,TDest>()
手动创建映射表达式,并在复杂类型上查找 null 检查以查看是否是相同的情况。
使你的 prop 可空
public decimal? MyComplexTypeProperty1 { get;set; }
然后使用这个映射
Mapper.CreateMap<MyEntityType, MyComplexType>()
.ForMember(p => p.MyComplexTypeProperty1, p => p.AllowNull())
如果你想解决所有复杂类型的问题,那么你可以使用这段代码来创建MapperConfiguration
var config = new MapperConfiguration(cfg =>
{
cfg.ForAllPropertyMaps(p =>
p.SourceType == typeof(MyComplexType) ||
p.SourceType == typeof(AnotherComplexType) // || ...
//NOTE: if you have another ComplexTypes so remove prev lines
// and use this line to handle all of them
//p.SourceType.GetCustomAttributes(typeof(ComplexType))
(p, q) => { q.AllowNull(); }
);
//other configs
});
我遇到了
EF 8
的问题,因为它允许再次使用 ComplexTypes
。
这里的问题是.Net 8中的
ComplexTypes
不应该为空,所以解决方案是避免空值。
AutoMapper
Api 也有变化,我需要调用 Internal()
才能访问 ForAllPropertyMaps()
。
因此,基于这个答案,最新版本中此问题的解决方案是:
using AutoMapper.Internal;
class MapProfile : Profile
{
public MapProfile()
{
// Per Map
CreateMap<MyEntityType, MyComplexType>()
.ForMember(p => p.MyComplexTypeProperty1, p => p.DoNotAllowNull());
// Or for all maps (don't forget the using above)
this.Internal().ForAllPropertyMaps(p =>
p.SourceType == typeof(MyComplexType) ||
p.SourceType == typeof(AnotherComplexType)
,
(p, q) => {
// Null Complex Types are not supported in .Net 8, so don't allow it.
q.DoNotAllowNull();
}
);
}
}