【问题标题】:Searching Against Projected EF Core Navigation Properties搜索投影的 EF Core 导航属性
【发布时间】:2020-10-27 22:58:37
【问题描述】:

使用 EF Core 3.1,我正在尝试在将可空导航属性(也称为左连接)投影为不同类型后对其执行搜索。

例如:

var dtos = await query
    .Select(x => new RootEntityDto
    {
        // ...

        Nested = x.NestedId.HasValue
            ? new NestedEntityDto
            {
                // ...

                Description = x.Nested.Description
            }
            : null
    })
    .Where(x => x.Nested.Description.Contains("2"))
    .ToArrayAsync();

问题是,它给了我一个可能有条件地导致 null 的三元错误:

The LINQ expression 'DbSet<RootEntity>
    .LeftJoin(
        outer: DbSet<NestedEntity>, 
        inner: f => EF.Property<Nullable<int>>(f, "NestedId"), 
        outerKeySelector: o => EF.Property<Nullable<int>>(o, "Id"), 
        innerKeySelector: (o, i) => new TransparentIdentifier<RootEntity, NestedEntity>(
            Outer = o, 
            Inner = i
        ))
    .Where(f => EF.Property<Nullable<int>>(f.Inner, "Id") != null ? new NestedEntityDto{ 
        Description = f.Inner.Description, 
    }
     : null.Description.Contains("2"))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

如果我在将实体投影到 DTO 之前尝试完全相同的事情,我没有问题:

var entities = await query
    .Where(x => x.Nested.Description.Contains("2"))
    .ToArrayAsync();

我意识到简单的解决方案是在投影发生之前执行Where 语句,但这不是一个选项。为了说明意图,对上述示例进行了简化。我也对评估查询客户端不感兴趣,因为我不知道三元组的更好替代方案。

理想情况下,我只是在寻找有条件地投射左连接导航属性的最佳实践,这样我仍然可以对其执行搜索。

编辑:我决定尝试 AutoMapper 10.1.1 并收到类似的错误:

var dtos = await query
    .ProjectTo<RootEntityDto>(_mapper.ConfigurationProvider, x => x.Nested)
    .Where(x => x.Nested.Description.Contains("2"))
    .ToArrayAsync();
The LINQ expression 'DbSet<RootEntity>
    .LeftJoin(
        outer: DbSet<NestedEntity>, 
        inner: f => EF.Property<Nullable<int>>(f, "NestedId"), 
        outerKeySelector: o => EF.Property<Nullable<int>>(o, "Id"), 
        innerKeySelector: (o, i) => new TransparentIdentifier<RootEntity, NestedEntity>(
            Outer = o, 
            Inner = i
        ))
    .Where(f => EF.Property<Nullable<int>>(f.Inner, "Id") == null ? null : new NestedEntityDto{ 
        Description = f.Inner.Description
    }
    .Description.Contains("2"))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

【问题讨论】:

    标签: c# entity-framework-core projection navigation-properties


    【解决方案1】:

    EF Core 3 完全改变了查询的评估方式,并非所有查询构造都受支持。我怀疑在 DTO 投影之后尝试过滤是这里的根本问题。您能否使用此查询测试升级到 EF Core 5 并查看它是否仍然失败,以及 5 支持更多查询模式。

    【讨论】:

    • 将 Microsoft.EntityFrameworkCore.SqlServer 从 3.1.9 升级到 5.0.0-rc.2.20475.6 后出现同样的错误。
    • 事实证明 EF Core 5 和 AutoMapper 的组合可以处理这个问题,但不能单独处理。
    【解决方案2】:

    我对 AutoMapper 所做的事情进行了一些研究,并发现了一个可行的约定:

    var dtos = await query
        .Select(x => new RootEntityDto
        {
            // ...
    
            Nested = x.Nested == null
                ? null
                : new NestedEntityDto
                {
                    // ...
    
                    Description = x.Nested.Description
                }
        })
        .Where(x => x.Nested.Description.Contains("2"))
        .ToArrayAsync();
    

    请注意,我倒置了三进制并且将本来应该是 !x.NestedId.HasValue 的内容切换为 x.Nested == null。但即使进行了这些更改,我仍然必须升级到 EF Core 5。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-22
      • 2018-10-10
      • 2020-02-23
      • 2022-09-23
      • 1970-01-01
      • 2022-01-04
      • 1970-01-01
      相关资源
      最近更新 更多