我在一个项目中遇到了一个问题,并在一个简单的测试项目中成功地重新提出了这个问题。
我有以下DTO:
public class AppUserDto
{
public int Id { get; set; }
public string Name { get; set; }
}
public class IssueDto
{
public int Id { get; set; }
public AppUserDto Owner { get; set; }
public AppUserDto Creator { get; set; }
}
相应的模型是完全相同的,只是有模型关系而不是DTO(显然)。
自动应用程序配置:
Mapper.CreateMap<AppUser, AppUserDto>().MaxDepth(1);
Mapper.CreateMap<Issue, IssueDto>().MaxDepth(1);
最简单的查询:
var i = context.Issues.ProjectTo<IssueDto>().FirstOrDefault();
这总是抛出一个
NotSupportedException
:The type 'AppUserDto' appears in two structurally incompatible initializations within a single LINQ to Entities query. A type can be initialized in two places in the same query, but only if the same properties are set in both places and those properties are set in the same order.
这当然是来自automapper的问题。
现在我尝试了以下方法:
Mapper.CreateMap<AppUser, AppUserDto>().MaxDepth(1)
.ProjectUsing(u => new AppUserDto
{
Id = u == null ? -1 : u.Id,
Name = u == null ? null : u.Name,
});
这使得
context.Issues.ProjectTo<IssueDto>()...
这样的查询成功。但这反过来又使AppUser
的直接映射产生空值(或id为0)。因此context.Users.ProjectTo<AppUserDto>().FirstOrDefault()
(甚至Mapper.Map<AppUserDto>(context.Users.FirstOrDefault())
)总是返回一个AppUserDto
,其中包含其道具的默认值。那么,如何使同一个基DTO中的同一类型的多个嵌套DTO对象在不牺牲所述DTO对象的直接映射的情况下工作呢?
用projectusing解决这个问题(如果我们可以让直接映射同时工作的话)并不理想,但是如果这是唯一的方法,我可以管理。
编辑:
很可能有一个bug,this is the github issue适合感兴趣的人。
最佳答案
罪魁祸首实际上是MaxDepth
调用本身。似乎不是这样,但在每个映射上粘贴MaxDepth
可能会产生副作用,正如我所看到的。
事实证明,我的dto上根本没有递归(这就是MaxDepth
的作用)。所以只要删除所有的MaxDepth
调用就可以解决这个问题,而不需要ProjectUsing
。
这已被清除here。