【问题标题】:How do I correctly use EF Core with AutoMapper ProjectTo and Unions?如何正确使用 EF Core 与 AutoMapper ProjectTo 和 Unions?
【发布时间】:2018-02-18 01:58:25
【问题描述】:

我的设置

  • 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 和 Entity Framework (Core) 抛出异常消息:

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 实体,没有例外。


执行计划

这是一个工作计划(有一个工会):

{value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[Test.Module.Entities.Person]).Where(entity => ((entity != null) And ((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]))}

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

{value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[Test.Module.Entities.Person]).Where(entity => ((entity != null) And ((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])).Select(dto => new PersonDetail() {FirstName = dto.FirstName, LastName = dto.LastName, Deleted = dto.Deleted, Age = dto.Age, CreatedUtc = dto.CreatedUtc, CreatedBy = dto。 CreatedBy, Id = dto.Id, RecordVersion = dto.RecordVersion, DisplayLabel = ((dto.FirstName + " ") + dto.LastName)})}


注意:

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

Ia 还在各自的 GitHub 项目上打开了问题:

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

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

【问题讨论】:

  • 感谢@LucianBargaoanu!这非常有帮助,并帮助我发现这实际上是工会的一个问题。我没有意识到我的查询被进一步操纵,而联合实际上是计划的一部分。我已更新问题以反映这一点。

标签: c# automapper union projection ef-core-2.0


【解决方案1】:

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

【讨论】:

    【解决方案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();
    

    【讨论】:

    • 嗨@ChrisR,感谢您的回复。我现在已将问题更改为与工会相关,因为我们发现这实际上是导致我们问题的原因。
    • 你想得到什么结果,所有名字为“Joe”且年龄超过 30 岁的人?
    • 不,这只是一个轻量级的例子(我知道在那个例子中我可以在非联合查询中使用 where 子句)。这个例子的重点是,即使是简单的联合也行不通。在某些情况下,我们对工会有合法的需求,但我觉得这没有任何价值,只是让这个问题更加混乱。看来实际的工会可能会破裂。
    • 澄清,我觉得展示一个更复杂的联合没有任何价值,因为我们可能需要解释它背后的数据,这不是重点。
    猜你喜欢
    • 2021-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    • 2021-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多