【问题标题】:Group by JsonDocument's property with unknown type using Entity Framework Core使用 Entity Framework Core 按类型未知的 JsonDocument 属性分组
【发布时间】:2020-11-02 22:19:35
【问题描述】:

我正在使用 Entity Framework Core 3.1.5

我正在尝试按 JsonDocument 的某些属性对实体进行分组,我不知道它的类型。 AdditionalData 是实体的JsonDocument 属性。

我需要在数据库上执行命令。

我设法做到了有两个限制

  1. 我指定了属性的类型(使用 GetInt32)
  2. 这些命令是在客户端而不是数据库上执行的。
    IEnumerable<MetricEntity> metricEntities = _tenantDbContext.Set<MetricEntity>();
    var ii2 = metricEntities.Where(metric => metric.Name == metricName).GroupBy(e =>
        e.AdditionalData!.RootElement.GetProperty(groupByProperty).GetInt32())
    .Select(entities => new
    {
        Count = entities.Count(), MetType = entities.Key, Ent = entities,
    }).ToList();

我也设法做到了,但没有得到结果中的所有实体 并且限制命令是在客户端而不是数据库上执行的。

var i2 = _tenantDbContext.Set<MetricEntity>()
.Where(metric => metric.Name == metricName)
.GroupBy(e =>
    e.AdditionalData!.RootElement.GetProperty(groupByProperty).GetString())
.Select(entities => new
{
    Count = entities.Count(), MetType = entities.Key
}).ToList();

但是当我将实体添加到结果中时,如下所示:

var i2 = _tenantDbContext.Set<MetricEntity>()
.GroupBy(e =>
    e.AdditionalData!.RootElement.GetProperty(groupByProperty).GetString())
.Select(entities => new
{
    Count = entities.Count(), MetType = entities.Key, ent = entities,
}).ToList();

我收到以下异常:

System.InvalidOperationException: Processing of the LINQ expression '(GroupByShaperExpression:
KeySelector: ((m.AdditionalData)#>>{(@__groupByProperty_1)}),
ElementSelector:(EntityShaperExpression:
    EntityType: MetricEntity
    ValueBufferExpression:
        (ProjectionBindingExpression: EmptyProjectionMember)
    IsNullable: False
)
)' by 'RelationalProjectionBindingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitNew(NewExpression newExpression)
   at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)

【问题讨论】:

    标签: c# entity-framework linq group-by entity-framework-core-3.1


    【解决方案1】:

    每个group by 查询应包含一个或多个 和其他仅在选择语句中具有聚合功能的属性(SumCount 等)。 EF 尝试将 LINQ 转换为 SQL 查询并由于没有内部检查而引发异常。

    有一个解决方法:

    GroupBy 之前评估表数据。以下代码加载所有MetricEntities 并将其分组到c# 代码中:

    var i2 = _tenantDbContext.MetricEntities
    .AsEnumerable()
    .GroupBy(e =>
        e.AdditionalData!.RootElement.GetProperty(groupByProperty).GetString())
    .Select(entities => new
    {
        Count = entities.Count(), MetType = entities.Key, ent = entities,
    }).ToList();
    

    【讨论】:

    • 我需要在数据库中执行命令,而不是在客户端。
    • 在结果中您将获得所有实体,因此不必在哪里执行您的查询。从表中选择所有数据会比按条件分组和选择数据更快。
    • 这很重要,因为在我在问题中编写的操作之后,我打算以某种方式聚合数据(也在数据库中),所以我不会从数据库中获取所有实体。我负担不起从数据库中获取数以千计的条目。这需要太多时间。
    • 很抱歉,您已经完成了:` .Select(entities => new { Count = entity.Count(), MetType = entity.Key, ent = entity, }) ` 每条返回的记录都将包含ent,其中包含表中的所有数据。
    • 我在 github 上的官方 repo 上发现了很多未解决的问题。似乎 EF Core 3.1 不完全支持 GroupByissue1, issue2
    猜你喜欢
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    • 2017-07-29
    • 2019-05-10
    • 2020-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多