2015-09-30 47 views
3

要跳過痛苦,請轉到編輯下面。AutoMapper奇怪的IQueryable投影異常


我使用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; } 
} 

而且我有以下的DTO:

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

    public DateTimeOffset Created { get; set; } 

    // If I remove this (or ignore it), everything works. 
    public SemesterDto Semester { get; set; } 
} 

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

    public string Name { get; set; } 
} 

配置:

Mapper.CreateMap<Semester, SemesterDto>().MaxDepth(1); 
Mapper.CreateMap<Article, ArticleDto>().MaxDepth(1); 

查詢:

context.Articles.Include(a => a.Semester) 
       .OrderByDescending(a => a.Created) 
       .Take(5) 
       .ProjectTo<ArticleDto>() 
       .ToList(); 

執行查詢得到以下奇怪的例外:

System.ArgumentException: Property 'NS.Models.Semester Semester' is not defined for type 'NS.Models.Semester' 

這是一些堆棧跟蹤:

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生成正在尋找一個Semester屬性的表達式(在ArticleDto.Semester似乎)在NS.Models.Semester類型當然不存在。 我能得到它的工作,如果我做到以下幾點:

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

但是,這只是我試圖通過使用AutoMapper避免寫的東西!

這可能是我的錯,但我找不到任何可疑的東西。

編輯:

我有SemesterDto以下構造函數:

public SemesterDto() 
{ 
} 

public SemesterDto(int key, string name) 
{ 
    Key = key; 
    Name = name; 
} 

當我刪除第二個一切正常。似乎是這樣,但這真是奇怪的行爲。我從來沒有想過ctor會出問題,所以我沒有把它包括進去,但一切皆有可能。對於那個很抱歉。

那麼,這是一個來自AutoMapper的錯誤還是有其他我誤解?

編輯2:

剝線這個更多,我試圖映射SemesterSemesterDto直接,這是結果:

context.Semesters.ProjectTo<SemesterDto>().FirstOrDefault(); 

NotSupportedException: Only parameterless constructors and initializers are supported in LINQ to Entities.

這加強的設想,即構造函數正在造成奇怪的行爲。

+0

您使用AutoMapper的版本是什麼? – silkfire

+0

最新的,'4.0.4' – mrahhal

+0

'項目()。到()'工作正常嗎? –

回答

1

這已被證實爲錯誤,請參閱this github issue。現在,我想我會避免在我的DTO中使用ctors,直到promised下一個版本。

如果您有v4.1.0或以上,那麼這應該已經修復。

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

你需要告訴它使用Semester - >Dto.Semester映射。

+0

這反而給我以下異常:'LINQ to Entities不能識別方法'NS.Models.SemesterDto Map [Semester](System.Object)'方法...' – mrahhal

+0

你怎樣調用初始映射器? – Swati

+0

你的意思是?在另一個說明中,我嘗試了這個:'.ForMember(a => a.Semester,c => c.MapFrom(a => Mapper.Map (a.Semester)));'。 – mrahhal

1

我可以在第二次編輯中重現該問題。不知何故(我不知道AutoMapper足夠了解原因),參數化構造函數總是優先於AutoMapper中的無參數構造函數。而EF不支持其表達式樹中的參數化構造函數。

無論如何,你可以通過使用ConstructProjectionUsing解決這個問題:

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

** So ** close!這適用於直接映射到SemesterDto,但在SemesterDto嵌套在另一個dto中時失敗,但與以前不同,但具有不同的異常:System.InvalidOperationException:當從'VisitLambda'調用時,重寫類型爲'System.Linq.Expressions'的節點。 ParameterExpression'必須返回相同類型的非空值。或者,重寫'VisitLambda'並將其更改爲不訪問此類型的孩子。'我認爲你讓我們最接近問題的根源,所以我已經投票了。 – mrahhal

+0

嗯,對我來說,直接和嵌套投影是可以的。 –

+1

所以我發現這個異常實際上是由'ConstructProjectionUsing'造成的。當我刪除所有ctors但仍然使用'ConstructProjectionUsing'時,發生了同樣的異常('VisitLambda'異常) – mrahhal