EF Core 5 - 如何将 EF.Functions.Like 与映射到 JSON 字符串的自定义属性一起使用?
Posted
技术标签:
【中文标题】EF Core 5 - 如何将 EF.Functions.Like 与映射到 JSON 字符串的自定义属性一起使用?【英文标题】:EF Core 5 - How can I use EF.Functions.Like with a custom property that maps to a JSON string? 【发布时间】:2021-09-08 12:01:39 【问题描述】:在我的一个数据库模型中,我有一个自定义类型 (Dictionary<string, string>
) 的属性,该属性使用自定义转换器自动转换为 JSON 或从 JSON 转换,并存储为数据库中的 text
字段。我希望能够使用 mysql 的 LIKE
比较器在这个 JSON 字段中搜索一个字符串,但是我遇到了一个异常。我不关心 JSON 的结构,我可以将其视为一个简单的文本字段并以这种方式进行搜索。
这是我尝试的方法(Sku
是复杂类型):
var responseSet = database.Products.Where(p => EF.Functions.Like(p.Sku, "%query%"));
这是我得到的例外:
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: The LINQ expression 'DbSet<ProductObject>()
.Where(p => __Functions_0
.Like(
matchExpression: p.Sku, pattern: __Format_1))' could not be translated.
Additional information:
Translation of method 'Microsoft.EntityFrameworkCore.MySqlDbFunctionsExtensions.Like'
failed. If this method can be mapped to your custom function,
see https://go.microsoft.com/fwlink/?linkid=2132413 for more information.
异常中的链接指向一个带有大量交叉引用的长 git 问题,但我无法在其中找到任何有用的东西。
有什么方法可以防止此错误发生并在复杂字段中进行搜索?
【问题讨论】:
【参考方案1】:EF Core value converters 的基本问题是 LINQ 查询是针对客户端类型构建的,然后在后台将其转换为提供程序类型,并且没有标准方法来指定查询内的提供程序类型转换。
但是,转换有一个简单的技巧(在我对其他转换相关问题的一些回答中,例如 How can a JSON_VALUE be converted to a DateTime with EF Core 2.2?、Expression tree to SQL with EF Core 或 Comparing strings as dates using EF core 3),它适用于大多数 EF Core 关系数据库提供程序。
在这种情况下,您知道提供程序类型的 CLR 等效项是 string
,因此您可以使用以下强制转换
p => EF.Functions.Like((string)(object)p.Sku, "%query%")
需要到object
的中间转换来欺骗C# 编译器以接受实际的转换。 EF Core 翻译器足够聪明,可以将其删除(以及此处不需要的其他翻译器)。
【讨论】:
【参考方案2】:这不是一个受支持的功能,但有一个可能对您有用的解决方法。定义自定义数据库函数以将表达式显式转换为底层 db 类型。
public static string Cast(YourComplexType t) => throw new NotSupportedException();
modelBuilder.HasDbFunction(() => Cast(default))
.HasTranslation(args =>
var a = args.First();
return new SqlUnaryExpression(
ExpressionType.Convert,
a,
typeof(string),
new StringTypeMapping(a.TypeMapping.StoreType, DbType.String));
);
EF.Functions.Like(Cast(p.Sku), "%query%")
很遗憾,您无法定义通用数据库函数。参数都必须是提供者可以存储的类型,这排除了object
或接口。因此,您可能必须为每种可能的类型定义重载方法。
【讨论】:
谈到骇人听闻的事情,欺骗 C# 编译器的“双重转换”技术通常对大多数 EFC 关系数据库提供程序都有效。例如EF.Functions.Like((string)(object)p.Sku, "%query%")
两个答案似乎都是正确的,但@IvanStoev 似乎更简单,而且效果很好。如果您将其移至单独的答案,我会投票赞成。以上是关于EF Core 5 - 如何将 EF.Functions.Like 与映射到 JSON 字符串的自定义属性一起使用?的主要内容,如果未能解决你的问题,请参考以下文章