Linq 到 SQL 转换失败以及本地评估

Posted

技术标签:

【中文标题】Linq 到 SQL 转换失败以及本地评估【英文标题】:Linq to SQL translation Failing as well as Local Evaluation 【发布时间】:2020-04-09 07:08:31 【问题描述】:

好的,所以我有以下 linq to sql 查询:

var baseQuery = _context.AuditTransaction
    .Include(at => at.AuditEntityEntries)
    .ThenInclude(aee => aee.AuditPropertyEntries)
    .Where(at => auditTransactionFilter.Id == 0 || at.Id == auditTransactionFilter.Id)
    .Where(at =>
        string.IsNullOrWhiteSpace(auditTransactionFilter.UserName) ||
        at.UserName == auditTransactionFilter.UserName);


return baseQuery
    .Where(at => at.AuditEntityEntries.Any() || at.AuditEntityEntries
        .Any(ataee => auditTransactionFilter.AuditEntityEntries
            .Any(atfaee =>
                (atfaee.Id == 0 || ataee.Id == atfaee.Id) &&
                (string.IsNullOrWhiteSpace(atfaee.TableName) ||
                    ataee.TableName.ToLower().Contains(atfaee.TableName.ToLower()))
                &&
                (string.IsNullOrWhiteSpace(atfaee.KeyValues) ||
                    ataee.KeyValues.ToLower().Contains(atfaee.KeyValues.ToLower()))
                && (atfaee.AuditPropertyEntries.Any() || ataee.AuditPropertyEntries
                    .Any(atape => atfaee.AuditPropertyEntries
                        .Any(atfape =>
                            (atfape.Id == 0 || atape.Id == atfape.Id) &&
                            (string.IsNullOrWhiteSpace(atfape.PropertyName) ||
                                atape.PropertyName == atfape.PropertyName)
                            &&
                            (string.IsNullOrWhiteSpace(atfape.AuditType.ToString()) ||
                                atape.AuditType == atfape.AuditType)
                            &&
                            (atfape.PropertyValues == null ||
                                atape.PropertyValues.Contains(atfape.PropertyValues))
                        ))
                    )
            )

        ));

无论出于何种原因,当它运行时,我收到数百条警告,它们的各个部分无法翻译,将在本地进行评估。但是,查询运行并没有正确过滤掉不匹配项:返回数据库中的所有记录。

但是,当我返回 baseQuery.ToList().Where(...) 时,查询运行完美。

更新:即使是简单的查询,例如:

return baseQuery
     .Where(at => at.AuditEntityEntries.Any(ataee => auditTransactionFilter.AuditEntityEntries.Any(atfaee => atfaee.TableName == ataee.TableName)));

返回如下错误:

warn: Microsoft.EntityFrameworkCore.Query[20500]
      The LINQ expression 'where ([atfaee].TableName == [ataee].TableName)' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
      The LINQ expression 'Any()' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
      The LINQ expression 'where from AuditEntityEntry atfaee in __auditTransactionFilter_AuditEntityEntries_0 where ([atfaee].TableName == [ataee].TableName) select [atfaee] => Any()' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
      The LINQ expression 'where ([atfaee].TableName == [ataee].TableName)' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
      The LINQ expression 'Any()' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
      The LINQ expression 'where  ?= (Property([at], "Id") == Property([ataee], "AuditTransactionId")) =?' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]

我在这里做错了什么?

请帮忙。

【问题讨论】:

“当它运行时,我收到数百个警告”您在运行时收到警告? 此外,return 语句中的 Where 子句可以简化为第一个条件,因为 || 的第二部分是第一个的过滤版本(如果第一个是true,那么第二个永远是true)。您可以将其简化为return baseQuery.Where(at => at.AuditEntityEntries.Any() @Rufus,在运行时查询执行时会出现警告。谢谢,我已将所有多余的空安全检查修改为 .Any()。我仍然收到警告。 另外,我在嵌套迭代中添加了一个简单的尝试,但它失败了。我更新了问题以反映。 【参考方案1】:

好吧,我厌倦了试图找到解决 linq to sql 嵌套 Any() 语句的方法,所以,我从 LinqKit 中提取了一个 predicateBuilder 库。

var baseQuery = _context.AuditTransaction
    .Include(at => at.AuditEntityEntries)
        .ThenInclude(aee => aee.AuditPropertyEntries)
    .Where(at => auditTransactionFilter.Id == 0 || at.Id == auditTransactionFilter.Id)
    .Where(at => string.IsNullOrWhiteSpace(auditTransactionFilter.UserName) || at.UserName == auditTransactionFilter.UserName);


var queryPredicateBuilder = PredicateBuilder.New<AuditTransaction>();

foreach (var entityFilter in auditTransactionFilter.AuditEntityEntries)

    if(entityFilter.AuditPropertyEntries?.Count == 0)
    
        queryPredicateBuilder
            .Or(at => at.AuditEntityEntries
                    .Any(ataee => ataee.TableName.Contains(entityFilter.TableName)
                    && (ataee.KeyValues == entityFilter.KeyValues || string.IsNullOrWhiteSpace(entityFilter.KeyValues))));
    


foreach (var propertyFilter in auditTransactionFilter.AuditEntityEntries.SelectMany(atfaee => atfaee.AuditPropertyEntries))

    queryPredicateBuilder
        .Or(at => at.AuditEntityEntries
            .Any(ataee => ataee.TableName.Contains(propertyFilter.AuditEntityEntry.TableName)
            && (ataee.KeyValues == propertyFilter.AuditEntityEntry.KeyValues || string.IsNullOrWhiteSpace(propertyFilter.AuditEntityEntry.KeyValues))
            && ataee.AuditPropertyEntries
                .Any(atape => atape.PropertyName == propertyFilter.PropertyName && atape.PropertyValues.Contains(propertyFilter.PropertyValues))
        ));

return baseQuery.AsExpandable().Where(queryPredicateBuilder);

这完全成功了! 我不喜欢它,但它可以工作,而且我不确定如何生成动态 linq to sql 语句,该语句将正确翻译并对外部非原始列表进行如此多级别的嵌套任何检查。

我仍在等待更好的答案。

【讨论】:

以上是关于Linq 到 SQL 转换失败以及本地评估的主要内容,如果未能解决你的问题,请参考以下文章

将 sql 查询转换为 linq 查询

涉及 Max() 的 SQL 到 LINQ 转换

使用 NOT IN 的 SQL 到 LINQ 转换

无法通过 Linq 方法 Contains() 针对 char 数组检查字符串,因为该数组不是 String 类型,转换为 String 类型失败

无法在转换后的查询中访问表(普通 SQL 到 LINQ)

具有XPath查询的SQL到LINQ转换