如何编写 EF.Functions 扩展方法?

How do I write EF.Functions extension method?

我看到 EF Core 2 有 EF.Functions 属性 EF Core 2.0 Announcement which can be used by EF Core or providers to define methods that map to database functions or operators so that those can be invoked in LINQ queries。它包括发送到数据库的 LIKE 方法。

但我需要一种不同的方法,SOUNDEX() 不包括。如何编写这样一种方法,将函数传递给数据库,就像 DbFunction 属性在 EF6 中所做的那样?或者我需要等待 MS 实施它?本质上,我需要生成类似

的东西
SELECT * FROM Customer WHERE SOUNDEX(lastname) = SOUNDEX(@param)

EF.Functions 添加新的标量方法很容易 - 您只需在 DbFunctions class 上定义扩展方法即可。然而,提供 SQL 翻译很困难,需要深入研究 EFC 内部结构。

但是,EFC 2.0 还引入了一种更简单的方法,在 EF Core 2.0 的新功能 文档主题的 Database scalar function mapping 部分中进行了解释。

据此,最简单的方法是向 DbContext 派生的 class 添加一个静态方法,并用 DbFunction 属性标记它。例如

public class MyDbContext : DbContext
{
    // ...

    [DbFunction("SOUNDEX")]
    public static string Soundex(string s) => throw new Exception();
}

并使用这样的东西:

string param = ...;
MyDbContext db = ...;
var query = db.Customers
    .Where(e => MyDbContext.Soundex(e.LastName) == MyDbContext.Soundex(param));

您可以在不同的 class 中声明此类静态方法,但随后您需要使用 HasDbFunction fluent API.

手动注册它们

EFC 3.0 根据 https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#udf-empty-string

稍微改变了这个过程

在部分上下文中添加 CHARINDEX 的示例 class:

public partial class MyDbContext
{
    [DbFunction("CHARINDEX")]
    public static int? CharIndex(string toSearch, string target) => throw new Exception();

    partial void OnModelCreatingPartial(
        ModelBuilder modelBuilder)
    {
        modelBuilder
            .HasDbFunction(typeof(MyDbContext).GetMethod(nameof(CharIndex)))
            .HasTranslation(
                args =>
                    SqlFunctionExpression.Create("CHARINDEX", args, typeof(int?), null));
    }
}