【发布时间】:2021-03-04 04:48:41
【问题描述】:
考虑以下 C# 代码:
CompiledQuery.Compile<IDataContext, int>((ctx, someId) =>
ctx
.GetTable<SomeTable>()
.Where(x => x.SomeId == someId /* complex filtering here */)
.AsCte("filtered")
.Join(
ctx.GetTable<AnotherTable>(),
SqlJoinType.Left,
(filtered, another) => filtered.Id == another.SomeId,
(filtered, another) => new { filtered.Id, another.SomeInteger }
)
.GroupBy(x => x.Id, x => x.SomeInteger)
.Select(x => new { x.Key, Sum = DataExtensions.AsNullable(x.Sum()) })
.AsCte("grouped")
)
假设这部分查询产生了如下的SQL(使用PostgreSQL方言):
WITH filtered AS (
SELECT "Id", "IntegerValue" FROM "SomeTable"
WHERE "SomeId" = @some_id
), grouped AS (
SELECT filtered."Id", SUM(another."SomeInteger") as "Sum"
FROM filtered
LEFT JOIN "AnotherTable" another
ON filtered."Id" = another."SomeId"
GROUP BY filtered."Id"
)
我想要的是继续这个查询以生成最终的 CTE,比如
SELECT filtered."Id" "FilteredId", grouped."Id" "GroupedId"
FROM grouped
INNER JOIN filtered /*LINQ problem here: "filtered" is not saved to a variable to reference it one more*/
ON filtered."SomeInteger" = grouped."Sum" OR grouped."Sum" IS NULL
从上例中的评论可以看出,filtered 已经被使用后,似乎无法引用它。所以问题是:有没有办法在查询的最后部分(分组后)引用filtered?
不包括第二个 CTE 用法(如窗口函数或子查询用法)的变通方法不在此问题的范围内。
由于Compile 方法接受表达式,因此适用 System.Linq.Expressions 限制:没有 ref/out/async/await/ValueTuple 等。不过,可以通过 F# 元组解决 ValueTuple 限制。
如果有办法可以帮助表达式树 AST 重写,则可以考虑(无论如何,我正在将嵌套的 lambdas 从 F# 表示转换为 linq2db 期望的表示)。
【问题讨论】:
标签: c# .net-core f# abstract-syntax-tree linq2db