c# - 如何在 Linq 查询中使用方法或表达式?
问题描述
我们在 Entity Framework 6 中将存储过程转换为 Linq 查询。
它有一个子查询not exists
,我们用它翻译成Any()
. 因为它有相当多的条件运算符,我想提取一个或方法。我可以用 an 来做一次检查,Expression<Func<TableRecord , bool>>
但我不能用 AND 来扩展它。
这是(简化的)原始 SQL 查询:
SELECT
main.Id,
main.VersionNumber,
main.ClosingVersion
FROM TableRecord main
WHERE
and not main.status = 'in progress'
and not exists(select sub.Id from TableRecord sub
where
(sub.tbrId = main.tbrId
and
( sub.VersionNumber > main.VersionNumber
or
(sub.VersionNumber = main.VersionNumber and
sub.ClosingVersion = 'z' and main.ClosingVersion is null)
)
)
)
这是 EF Linq 语句(其中部分):
TableRecord.Where(main =>
!TableRecord.Any(sub =>
sub.tbrId == main.tbrId &&
(sub.VersionNumber > main.VersionNumber
||
sub.VersionNumber == main.VersionNumber &&
sub.ClosingVersion == "z" && main.ClosingVersion == null)));
如果我用一个表达式提取整个子查询,那仍然给我留下相同的运算符和一个异常:System.InvalidOperationException:从范围''引用的'TableRecord'类型的变量'main',但它没有定义:
public void MainMethod()
{
...
TableRecord.Where(main =>
!TableRecord.Any(SubQueryExpression(main)));
}
private static Expression<Func<TableRecord , bool>> SubQueryExpression(TableRecord main)
{
return sub =>
sub.tbrId == main.tbrId &&
(sub.VersionNumber > main.VersionNumber
||
sub.VersionNumber == main.VersionNumber &&
sub.ClosingVersion == "z" && main.ClosingVersion == null)));
}
最初我正在考虑使用本地函数:
private static Expression<Func<TableRecord , bool>> SubQueryExpression(TableRecord main)
{
return sub =>
sub.tbrId == main.tbrId &&
(sub.VersionNumber > main.VersionNumber
||
sub.VersionNumber == main.VersionNumber &&
VersionEqualAndClosing(sub));
bool VersionEqualAndClosing(TabelregelVersie sub)
{
return sub.VersionNumber == main.VersionNumber && sub.ClosingVersion == "z" && main.ClosingVersion == null;
}
}
有没有办法提取方法或表达式?让 Sonar 更易于阅读并让 Sonar 满意。
解决方案
安装 LINQKit 并重写你的方法:
[Expandable(nameof(SubQueryExpressionImpl))]
private static bool SubQueryExpression(TableRecord main, TableRecord sub)
{
throw new NotImplementedException();
}
private static Expression<Func<TableRecord, TableRecord, bool>> SubQueryExpressionImpl()
{
return (main, sub) =>
sub.tbrId == main.tbrId &&
(sub.VersionNumber > main.VersionNumber
||
sub.VersionNumber == main.VersionNumber &&
VersionEqualAndClosing(main, sub));
}
[Expandable(nameof(VersionEqualAndClosingImpl))]
public static bool VersionEqualAndClosing(TabelregelVersie main, TabelregelVersie sub)
{
throw new NotImplementedException();
}
private static Expresion<Func<TabelregelVersie, TabelregelVersie, bool>> VersionEqualAndClosingImpl()
{
return (main, sub) => sub.VersionNumber == main.VersionNumber && sub.ClosingVersion == "z" && main.ClosingVersion == null;
}
然后您可以通过以下方式使用它们:
public void MainMethod()
{
...
TableRecord
.AsExpandable()
.Where(main =>
!TableRecord.Any(sub => SubQueryExpression(main, sub)));
}
推荐阅读
- java - 我不能用 spark 写一个 orc 文件
- javascript - 以编程方式创建未定义的类
- python - 如何解决:“列表索引必须是整数或切片,而不是 str”
- r - 在 RStudio 中使用逐字代码块时 knitr 的副作用
- rust - 锈溢出左移
- java - 具有数据加密功能的 PostgreSQL JDBC 驱动程序
- ember.js - 当我在 transitionTo() 中添加 queryParam 时,我的 ember 应用程序完全重新加载
- python - 我已将连续特征转换为分类特征。我在 Pandas 中得到 NaN
- google-apps-script - 在 AG 列中查找 lastRow
- ruby-on-rails - 通过 rspec 字符串化/解析请求数据