如何在 IQueryable 的 where 子句中调用函数

Posted

技术标签:

【中文标题】如何在 IQueryable 的 where 子句中调用函数【英文标题】:How to call a function inside a where clause of IQueryable 【发布时间】:2021-12-10 15:04:38 【问题描述】:

我想在 IQueryable 语句中执行 Where 子句,这样它将在数据库端完成,而不是在客户端进行选择。我现在的代码是:

var all = await session.Query<Instance>()
    .ToListAsync()
    .ConfigureAwait(false);
var insts = all.Where(i => ruleInstances.Contains(i.Name,
    new ComparerExtension<string>(
        (x, y) => string.Compare(x, y, StringComparison.OrdinalIgnoreCase) == 0,
            h => h.ToLower().GetHashCode())));

在客户端选择哪个。

理想情况下,我可以按如下方式编写 IQueryable:

var all = await session.Query<Instance>()
    .Where(i => ruleInstances.Contains(i.Name,
        new ComparerExtension<string>(
            (x, y) => string.Compare(x, y, StringComparison.OrdinalIgnoreCase) == 0,
                h => h.ToLower().GetHashCode())))
    .ToListAsync()
    .ConfigureAwait(false);

但是,这种理想的编码是行不通的。我得到一个例外:“无法理解表达式......”指的是整个 where 子句。

到目前为止,我认为我需要将ruleInstances.Contains(...) 方法表达为表达式树。

我将不胜感激设置它。

谢谢。

【问题讨论】:

您是否尝试过加入?我不确定这是否允许它在服务器端运行,或者它是否仍然在内部关闭 Instances 在执行连接之前 - 但你可以试一试 - 像这样:.Join(ruleInstances, i =&gt; i.Name, r =&gt; r, (i, r) =&gt; i, StringComparer.OrdinalIgnoreCase).ToList(); 如您所述,需要构建表达式树。通过实施您的 ComparerExtension 来改进您的问题。它是 NHibernate 吗? 【参考方案1】:

您的ComparerExtension 的实例化和调用无法在服务器端完成,因此无法转换为在那里运行。请注意,最后,库必须创建要发送到服务器的 SQL 语句,并且没有函数或类似的。如果您需要在服务器端进行不区分大小写的比较,则必须确保服务器对数据库使用正确的排序规则(例如 SQL_Latin1_General_CP1_CI_AS),在这种情况下您可以发送:

.Where(i => ruleInstances.Contains(i.Name))

如果这真的有效,取决于 ruleInstances 的类型。也许您必须将其转换为简单的字符串列表并使用:

var ruleInstanceNames = ruleInstances.Select(rule => rule.Name).ToList();

... .Where(i => ruleInstanceNames.Contains(i))

【讨论】:

以上是关于如何在 IQueryable 的 where 子句中调用函数的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate LinqProvider / IQueryable:在 Where 子句中是不是支持 FirstOrDefault()?

将 IQueryable where 子句从 DTO 映射到实体

实体框架,如何将 IQueryable 与多个 where 转换为 SQL 一起使用?

Linq to Entities 添加 Where 子句以在另一个表中查找 EXISTS

在循环中使用 IQueryable 的实体框架 WHERE OR 查询

EF 6.x,LINQ-to-SQL和原始SQL子句