如何在AutoMapper ProjectTo和Unions中正确使用EF Core?

时间:2018-02-18 01:58:25

标签: automapper union asp.net-core-2.0 projection ef-core-2.0

我的设置

  • ASP.NET Core 2.0
  • EntityFrameworkCore 2.0.1
  • AutoMapper 6.2.2

问题

我有一个名为PersonDetail的DTO项目和名为Person的实体。 当我打电话

db.People.Where(p => p.FirstName == "Joe").Union(db.People.Where(p => Age > 30)).ProjectTo<PersonDetail>(mapperConfig).ToList(); 

我没有得到PersonDetail DTO和实体框架(核心)抛出异常消息:

  

ArgumentException:输入序列必须包含“Test.Module.Entities.Person”类型的项目,但它包含“Test.Module.Dtos.PersonDetail”类型的项目。

没有问题的示例

当我运行代码时:

 db.People.Where(p => p.FirstName == "Joe").Union(db.People.Where(p => Age > 30)).ToList(); 

我得到了Person个实体,没有例外。

执行计划

这是一份工作计划(带工会):

  

{值(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1 [Test.Module.Entities.Person])其中(实体=&GT;!((实体= NULL)和((63ed0ebd-2c02-4496- ac8d-b836cbf13259 == entity.CreatedBy)或(393a6bb0-b437-4664-beb0-6800f509451b == entity.CreatedBy))))。Union(value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1 [Test.Module。 Entities.Person]))}

现在这是相同的计划,但也有自动播放器投影:

  

{值(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1 [Test.Module.Entities.Person])其中(实体=&GT;!((实体= NULL)和((63ed0ebd-2c02-4496- ac8d-b836cbf13259 == entity.CreatedBy)或(393a6bb0-b437-4664-beb0-6800f509451b == entity.CreatedBy))))。Union(value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1 [Test.Module。 Entities.Person]))选择(DTO =&GT;新PersonDetail(){姓= dto.FirstName,名字= dto.LastName,已删除= dto.Deleted,年龄= dto.Age,CreatedUtc = dto.CreatedUtc,CreatedBy = dto.CreatedBy,Id = dto.Id,RecordVersion = dto.RecordVersion,DisplayLabel =((dto.FirstName +“”)+ dto.LastName)})}

注意:

我只是调用ToList来将此问题减少到它的最小形式。我知道在这个例子中我似乎不需要使用ProjectTo。在我的实际代码中,我们使用OData,我们需要将最终结果作为DTO作为Queryable对象的投影查询。我也明白,这个联盟并不是一个很好的联盟例子,仅仅是为了简化联盟问题。

Ia还在相应的GitHub项目上打开了问题:

EntityFrameworkCore https://github.com/aspnet/EntityFrameworkCore/issues/11033

AutoMapper https://github.com/AutoMapper/AutoMapper/issues/2537

2 个答案:

答案 0 :(得分:3)

这是一个EF Core错误,它已在EF Core 2.1中修复 https://github.com/aspnet/EntityFrameworkCore/issues/11033

答案 1 :(得分:2)

如果没有更多细节,很难确切地知道出了什么问题,但请确保您的映射是正确的,例如如果使用映射配置文件

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Person, PersonDetail>();
    }
}

假设您的EF上下文有一组:

public virtual DbSet<Person> People { get; set; }

然后您应该能够查询上下文和项目,如下所示:

var details = _context.People
    .Where(p => p.LastName == 'Smith')
    .OrderBy(p => p.FirstName)
    .ProjectTo<PersonDetail>
    .ToList();

您不需要AsNoTracking,因为EF不会跟踪非实体的结果类型,请参阅Tracking and projections上的文档

---更新---

以下内容应该有效,尽管EF Core会在内存中对其进行评估:

var firstNameQuery = db.People
    .Where(p => p.FirstName == "Joe")
    .ProjectTo<PersonDetail>(mapperConfig);
var ageQuery = db.People
    .Where(p => p.FirstName == "Joe")
    .ProjectTo<PersonDetail>(mapperConfig);
var results = firstNameQuery.Union(ageQuery).ToList();