AutoMapper IQueryable 扩展抛出“无法比较类型 <Complex Type> 的元素”与

问题描述 投票:0回答:3

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
子句中,会出现上述错误,但这里显然不是这种情况。

c# entity-framework automapper
3个回答
6
投票

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 检查以查看是否是相同的情况。


2
投票

使你的 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
});

0
投票

我遇到了

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();
        }
    );
  }
}

© www.soinside.com 2019 - 2024. All rights reserved.