c# - 使用 EF Core 到 SQL 的表达式树
问题描述
我们有一列将 JSON 数据存储为字符串。此 JSON 数据通过物化被读取并转换为IDictionary<string, object>
. 这一切都很好,直到我想过滤它。仅在从数据库中获取数据后才应用过滤。我们将拥有数百万条记录,因此这是不可接受的。我的过滤器显然被 EF Core 完全忽略为 WHERE 子句,因为它可能不知道如何解析 MethodCallExpressions。
我正在寻找一种方法来尽可能接近我在下面使用我拥有的表达式树的 SQL 查询。
我需要转换这个:
.Call System.Linq.Queryable.Where(
.Constant<QueryTranslator`1[Setting]>(QueryTranslator`1[Setting]),
'(.Lambda #Lambda1<System.Func`2[Setting,System.Boolean]>))
.Lambda #Lambda1<System.Func`2[Setting,System.Boolean]>(Setting $$it)
{
((System.Nullable`1[System.Int32]).If (
$$it.Value != null && .Call ($$it.Value).ContainsKey("Name")
) {
($$it.Value).Item["Name"]
} .Else {
null
} > (System.Nullable`1[System.Int32]).Constant<Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int32]>(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int32]).TypedProperty)
== .Constant<System.Nullable`1[System.Boolean]>(True)
}
进入这个:
SELECT *
FROM [Setting]
WHERE JSON_VALUE([Value], 'lax $.Name') > 1; -- [Value_Name] > 1 is also fine
有了一个ExpressionVisitor
我已经成功地接近 WHERE [Value] = 'Something' 但这仅适用于字符串并且缺少键名。
解决方案
在它获得“官方”支持之前,您可以JSON_VALUE
使用 EF Core 2.0 引入的Database scalar function mapping进行映射。
例如,在上下文派生类或单独的静态类中添加以下静态方法,如下所示:
public static class MyDbFunctions
{
[DbFunction("JSON_VALUE", "")]
public static string JsonValue(string source, string path) => throw new NotSupportedException();
}
如果它在单独的类中,请将以下内容添加到您的上下文OnModelCreating
覆盖中(如果该方法在上下文中,则不需要):
modelBuilder.HasDbFunction(() => MyDbFunctions.JsonValue(default(string), default(string)));
现在您可以在 LINQ to Entities 查询中使用它,类似于EF.Functions
. 请注意该函数返回string
,因此为了欺骗编译器将其“转换”为数字,您可以使用如下所示的双重转换技术(在 EF Core 2.1.2 中测试和工作):
var query = db.Set<Setting>()
.Where(s => (int)(object)MyDbFunctions.JsonValue(s.Value, "lax $.Name") > 1);
这转化为所需的
WHERE JSON_VALUE([Value], 'lax $.Name') > 1
执行转换的另一种(可能类型更安全)方法是使用Convert
类方法(令人惊讶的是,SqlServer EF Core 提供程序支持):
var query = db.Set<Setting>()
.Where(s => Convert.ToInt32(MyDbFunctions.JsonValue(s.Value, "lax $.Name")) > 1);
这转化为
WHERE CONVERT(int, JSON_VALUE([Value], 'lax $.Name')) > 1
推荐阅读
- python - Keras tuner.search 搜索错误给我一个与形状相关的错误“形状(无,11,11)和(无,1000,11)不兼容”
- google-bigquery - 为什么 BigQuery 包装/舍入时间戳的最大值?
- javascript - 用多个空格替换多个
- c - 我不明白如何移位 16 位、8 位等。'&' 的组合检测偶数位中的 1
- swiftui - SwiftUI - 倒计时结束时,跳转到另一个视图
- python - 从具有相同索引号的多个列表中打印
- powerbi - 我可以将多个表连接到一个吗?
- python - 即使我在循环之外对其进行了初始化,Python 变量也会在每个循环中更新
- css - 如何在链接按钮内平均对齐 svg 图像和文本?
- javascript - 尝试在 MongoDB 中使用 updateOne(),但它没有更新文档或给我一个错误?