Использование SQL-Функций в Entity Framework
SQL Server (или другая база данных) имеет множество встроенных функций, которые можно использовать в запросах. Но в Entity Framework их нельзя использовать напрямую.
Некоторые функции имеют аналоги в .NET, например, для добавления дней к дате вы используете DATEADD в TSQL, а в C# это становится DateTime.AddDays. Но, например, SOUNDEX в TSQL (для поиска похожих строк вместо полного совпадения) не имеет C#-версии.
Вы можете написать свою реализацию на C# или просто зарегистрировать эти SQL-функции в DBContext. После регистрации функции вы можете использовать её в EF-запросах независимо от поставщика БД.
Зарегистрируем функцию SOUNDEX. Для этого создадим новый метод в DbContext и аннотируем его атрибутом DbFunction.
public class MyDbContext : DbContextЗамечание: реализовывать метод не надо, только предоставить правильную сигнатуру.
{
…
[DbFunction(Name = "SoundEx",
IsBuiltIn = true)]
public static string SoundEx(string input)
{
throw new NotImplementedException();
}
}
Теперь можно использовать метод SoundEx в запросах:
app.MapGet("/customers",
([FromQuery] name, MyDbContext ctx) => {
return ctx.Customers
.Where(c => MyDbContext.SoundEx(c.Name) ==
MyDbContext.SoundEx(customerName))
.ToListAsync();
});
Когда запрос выполняется, генерируется следующий код SQL:SELECT [c].[Id], [c].[Name]Функция по запросу "Timothy", вернёт также слова, вроде "Timmothy", "Timoteo" или "Timotheo".
FROM [Customers] AS [c]
WHERE SoundEx([c].[Name]) = SoundEx(N'Timothy')
OR ((SoundEx([c].[Name]) IS NULL)
AND (SoundEx(N'Timothy') IS NULL))
Чтобы убрать проверку на NULL, можно установить свойство IsNullable атрибута DbFunction в false:
[DbFunction(Name = "SoundEx",Помимо встроенных функций, вы также можете создавать собственные и аналогичным образом добавлять их в DbContext. Для пользовательских функций установите для свойства IsBuiltIn значение false, а также определите схему функции:
IsBuiltIn = true,
IsNullable = false)]
public static string SoundEx(string input)
{
throw new NotImplementedException();
}
[DbFunction(Name = "MyCustomFunction",Злоупотреблять этим не рекомендуется, но регистрация существующих функций может быть полезна при переносе существующей базы кода в более новую версию.
Schema = "dbo",
IsBuiltIn = false)]
public static int MyCustomFunction(int input)
{
throw new NotImplementedException();
}
Итого
В целом, использование DbFunctions может быть полезным способом воспользоваться преимуществами определённых функций базы данных в запросах EF. Но, поскольку вы используете функцию, специфичную для базы данных, становится сложнее переносить код на другие базы данных, если вы когда-нибудь захотите это сделать. В нашем примере функция
SOUNDEX существует не во всех базах данных или имеет другое имя. Если вы когда-нибудь захотите переключиться на другую базу данных, нужно будет пересмотреть все добавленные DbFunctions.Источник: https://timdeschryver.dev/blog/consuming-sql-functions-with-entity-framework