TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.77K subscribers
Post #2071 2.2K
День 1704. #ЗаметкиНаПолях
Использование 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]
FROM [Customers] AS [c]
WHERE SoundEx([c].[Name]) = SoundEx(N'Timothy')
OR ((SoundEx([c].[Name]) IS NULL)
AND (SoundEx(N'Timothy') IS NULL))

Функция по запросу "Timothy", вернёт также слова, вроде "Timmothy", "Timoteo" или "Timotheo".

Чтобы убрать проверку на NULL, можно установить свойство IsNullable атрибута DbFunction в false:
[DbFunction(Name = "SoundEx", 
IsBuiltIn = true,
IsNullable = false)]
public static string SoundEx(string input)
{
throw new NotImplementedException();
}

Помимо встроенных функций, вы также можете создавать собственные и аналогичным образом добавлять их в DbContext. Для пользовательских функций установите для свойства IsBuiltIn значение false, а также определите схему функции:
[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
  • 👍 17
More from @netdeveloperdiary
  1. Oct 9, 2026День 2809. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Окончание Начало 3.…
  2. Oct 8, 2026День 2808. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Начало В ИТ есть се…
  3. Oct 7, 2026День 2807. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Окончание Нач…
  4. Oct 6, 2026🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собес…
  5. Oct 6, 2026День 2806. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Начало Больши…
  6. Oct 5, 2026День 2805. #ЧтоНовенького #NET11 Аргументы в Выражениях Коллекций в C#15 В C#15 реализован…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →