Лучшая практика вызова скалярных функций с помощью Entity Framework Core (2.1)

Мне часто нужно вызывать скалярные функции, определенные на SQL Server, из моих веб-приложений (ASP.NET Core / EF Core). Поскольку эти функции являются простыми вспомогательными функциями, и я также использую их много, я использую общий шаблон для вызова этих скалярных функций - с помощью новых типов запросов, доступных в EF Core 2.1. Поскольку я относительно новичок в EF Core, мой вопрос в том, может ли этот шаблон вызвать проблемы и / или есть ли лучшее решение или лучший способ вызова скалярных функций. Решение работает, и я пока не могу наблюдать никаких проблем, но, например, мне было интересно, может ли использование одного и того же типа запроса для разных функций привести к неожиданным значениям или странному поведению из-за поведения кэширования / отслеживания и т. д. В EF Core - это больше похоже на внутреннее чувство.

Итак, вот шаблон: Вместо того, чтобы определять разные типы сущностей для каждой отдельной скалярной функции, я просто определяю один общий тип:

public class PrimitiveDto<T>
{
    public T Value { get; set; }
}

В моем классе контекста я регистрирую эти типы для каждого типа возвращаемого значения, которое я ожидаю от скалярных функций, которые я хочу использовать, поэтому для всех скалярных функций, возвращающих 'int', класс контекста будет иметь одну дополнительную запись, подобную этой:

public virtual DbQuery<PrimitiveDto<int>> BasicIntDto { get; set; }

Для EF Core> = 3 это:

public virtual DbSet<PrimitiveDto<int>> BasicIntDto { get; set; }

В каждой части приложения, где я хочу вызвать скалярную функцию, возвращающую int, я просто использую один и тот же следующий шаблон:

context.BasicIntDto.FromSql("SELECT <FUNCTION> AS Value")

Используя этот шаблон, я могу одинаково вызывать любое количество функций без определения дополнительных типов или расширения класса контекста.

Пожалуйста, дайте мне знать, могу ли я попасть в ловушку из-за этого шаблона. Большое спасибо.

Я не вижу в этом серьезных проблем, но вы, вероятно, можете немного реорганизовать его, чтобы вам не приходилось предоставлять весь запрос при каждом вызове. Создание свойства в контексте, которое возвращает BasicDto<int> для каждой функции / процедуры, например, принимает любые требуемые аргументы.

Bradley Uffner 03.07.2018 13:02

Вы правы - спасибо за идею.

Grimm 03.07.2018 13:26

Почему бы вам не использовать Отображение скалярных функций базы данных. Да, это требует расширения класса контекста, но не требует дополнительных типов и обеспечивает возможность повторного использования, поддержку Intelisense и проверку времени компиляции, как и в случае с обычными методами LINQ и CLR.

Ivan Stoev 03.07.2018 13:38

Спасибо за подсказку, Иван Стоев - должен признать, что я еще не знал об этой функции. Но оказывается, что вы не можете вызвать скалярную функцию напрямую через эту функцию - вы должны начать с типа объекта, а затем использовать эти заглушки метода в запросе (например, context.ENTITY.where (x => x.METHODSTUB ()) ...). Однако, похоже, они над этим работают (см. github.com/aspnet/EntityFrameworkCore/issues/9810). Итак, еще раз спасибо, что указали на это.

Grimm 03.07.2018 14:42

Вы можете использовать метод Enumerable.Single для получения результата.

Mark G 03.07.2018 15:42

Марк Дж. Не могли бы вы предоставить дополнительную информацию об этом? Это другой подход или вы просто имеете в виду, что я должен вызывать .Single () после .FromSql ()?

Grimm 03.07.2018 16:34

@ Гримм, правильно. Другой вариант - использовать ADO.NET с помощью GetDbConnection и ExecuteScalar.

Mark G 03.07.2018 16:44

Марк Джи, мне очень жаль, что я должен спросить еще раз, но что именно сейчас правильно?

Grimm 03.07.2018 19:17

Похоже на DbQuery не рекомендуется для EF Core 3, значит, это должен быть DbSet<PrimitiveDto<int>>.

Endy Tjahjono 23.02.2020 06:39

Это правда, просто замените в этом шаблоне DbQuery <...> на DbSet <...>.

Grimm 24.02.2020 12:56
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
10
7 283
1

Ответы 1

К сожалению, похоже, что эта функция была оставлена ​​в стороне: https://github.com/aspnet/EntityFrameworkCore/issues/9810

Можно заключить вызовы функций в статический класс, используя небольшую таблицу, которая никогда не бывает пустой:

public static class DbFunctions
{
   public static decimal MyFunctionABC(int param1, int param2)
   {
       using (var db = new MyDbContext())
       {
        return db.table.Take(1).Select(t => MyDbContext.MyFunctionABC(x, y)).Single();
       }
    }
 }

Тогда вы можете вызвать в DbFunctions.MyFunctionABC(x,y);

Другие вопросы по теме