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版本是什么?DoesProject().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());