Asp.net mvc 自动映射奇怪的IQueryable投影异常

Asp.net mvc 自动映射奇怪的IQueryable投影异常,asp.net-mvc,entity-framework,automapper,Asp.net Mvc,Entity Framework,Automapper,要跳过疼痛,请转到下面的编辑 我正在使用EF和AutoMapper IQueryableExtensions 我的两个模型如下: public class Article { public int Key { get; set; } public DateTimeOffset Created { get; set; } public int? SemesterKey { get; set; } public virtual Semester Semester

要跳过疼痛,请转到下面的编辑


我正在使用EF和AutoMapper IQueryableExtensions

我的两个模型如下:

public class Article
{
    public int Key { get; set; }

    public DateTimeOffset Created { get; set; }

    public int? SemesterKey { get; set; }
    public virtual Semester Semester { get; set; }
}

public class Semester
{
    public int Key { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Article> Articles { get; set; }

    // Other relationships
    public virtual ICollection<Subject> Subjects { get; set; }

    public virtual ICollection<AppUser> Users { get; set; }
}
配置:

Mapper.CreateMap<Semester, SemesterDto>().MaxDepth(1);
Mapper.CreateMap<Article, ArticleDto>().MaxDepth(1);
这是一些堆栈跟踪:

System.Linq.Expressions.Expression.Property(Expression expression, PropertyInfo property)
System.Linq.Expressions.Expression.MakeMemberAccess(Expression expression, MemberInfo member)
....
AutoMapper.MappingEngine.CreateMapExpression(ExpressionRequest request, Expression instanceParameter, IDictionary`2 typePairCount)
似乎AutoMapper在
NS.Models.sterm
类型上生成了一个表达式,该表达式正在查找
sterm
属性(响应
ArticleDto.term
似乎不存在)。 如果我执行以下操作,我可以使其工作:

Mapper.CreateMap<Article, ArticleDto>().MaxDepth(1)
      .ForMember(a => a.Semester, c => c.MapFrom(a => a.Semester == null ? null : new SemesterDto() {
                        Key = a.Semester.Key,
                        Year = a.Semester.Year }));
当我移除第二个时,一切正常。似乎就是这样,但这确实是一种奇怪的行为。我从来没有想过ctor会造成问题,所以为了清楚起见,我没有包括它,一切都是可能的,不是吗。很抱歉

那么,这是来自AutoMapper的bug还是我误解了什么

编辑2: 除此之外,我还尝试将
学期
直接映射到
学期
,结果如下:

context.Semesters.ProjectTo<SemesterDto>().FirstOrDefault();
context.semests.ProjectTo().FirstOrDefault();
NotSupportedException:LINQ to实体中只支持无参数构造函数和初始值设定项。

这强化了ctor导致奇怪行为的想法。

Mapper.CreateMap()
Mapper.CreateMap<Article, Dto.Article>()
      .ForMember(d => d.Semester, o => o.MapFrom(s => Mapper.Map<Dto.Semester>(s));
.ForMember(d=>d.sement,o=>o.MapFrom(s=>Mapper.Map));

你需要告诉它使用
学期
->
Dto.sement
映射。

我可以在你的第二次编辑中重现这个问题。不知怎的(我不太了解AutoMapper,不知道为什么),参数化构造函数始终优先于AutoMapper中的无参数构造函数。并且EF在其表达式树中不支持参数化构造函数

无论如何,您可以使用
ConstructionProjectionUsing
解决此问题:

Mapper.CreateMap<Semester, SemesterDto>().MaxDepth(1)
      .ConstructProjectionUsing(sem => new SemesterDto());
Mapper.CreateMap().MaxDepth(1)
.ConstructionProjectionUsing(sem=>new SemestedTo());

这已被确认为一个bug,请参阅。目前,我想在下一个版本之前,我将在DTO中避免使用CTOR


如果您有
v4.1.0
或更高版本,则应已修复此问题。

这反而会给我以下异常:
LINQ to Entities无法识别方法“NS.Models.semestedto Map[sement](System.Object)'方法…
您如何调用初始映射器?您的意思是什么?另一方面,我尝试了以下方法:
.ForMember(a=>a.sement,c=>c.MapFrom(a=>mapper.Map(a.sement)));
。此解决方案很可能只适用于内存中的映射。我制作了一些轻量级模型,但出现了相同的异常。您使用的AutoMapper版本是什么?Does
Project().To())
是否正常工作?同样的结果,同样的事情。我无法重新编程。也许你应该显示更多的细节,这样我们可能会看到你自己忽略的问题。我制作了一些轻量级模型只是为了测试,映射工作正常。现在我正试图排除导致此失败的差异。太接近了!当直接映射到SemestedTo时,这是有效的,但当SemestedTo与之前一样嵌套在另一个dto中时失败,但出现不同的异常:
System.InvalidOperationException:从“VisitLambda”调用时,重写类型为“System.Linq.Expressions.ParameterExpression”的节点必须返回同一类型的非空值。或者,重写“VisitLambda”并将其更改为不要去看这种类型的孩子。
我想你让我们最接近问题的根源,所以我已经投了赞成票。嗯,对我来说,直接和嵌套投影是可以的。所以我发现这个异常实际上是由使用
ConstructProjectionUsing
引起的。当我删除所有的CTOR,但继续使用
ConstructProjectionUsing时ing
发生了相同的异常(
VisitLambda
异常)你的代码中一定有什么东西不能很好地使用AutoMapper。对我来说,使用
ConstructionProjectionUsing
也可以,而且没有参数化的构造函数。我现在有点困惑。我现在真的很困惑,我尝试了一个非常简单的模型。像往常一样,直接映射可以工作,但映射到带有嵌套dto的dto失败。我想现在我只需要在我的余生中,避免使用automapper在我的DTO上使用CTOR。
public SemesterDto()
{
}

public SemesterDto(int key, string name)
{
    Key = key;
    Name = name;
}
context.Semesters.ProjectTo<SemesterDto>().FirstOrDefault();
Mapper.CreateMap<Article, Dto.Article>()
      .ForMember(d => d.Semester, o => o.MapFrom(s => Mapper.Map<Dto.Semester>(s));
Mapper.CreateMap<Semester, SemesterDto>().MaxDepth(1)
      .ConstructProjectionUsing(sem => new SemesterDto());