Каков рекомендуемый способ добавления хранимой процедуры SQL Server в модель Entity Framework

Резюме

В нашем приложении мы используем Entity Framework 6 и SQL Server 2016. При импорте в модель EF хранимую процедуру со сложной логикой, в частности при использовании временных таблиц, мы помещаем поверх:

SET FMTONLY OFF

Это заставляет хранимую процедуру выполнять полную логику и, следовательно, возвращать правильный выходной формат, что позволяет модели EF правильно генерировать сложный тип.

В целом работает нормально. Однако в документации Microsoft https://docs.microsoft.com/en-us/sql/t-sql/statements/set-fmtonly-transact-sql?view=sql-server-ver15 указано: Не используйте эту функцию. Поэтому мне интересно, какой рекомендуемый способ - импортировать хранимую процедуру и правильно сгенерировать сложный тип.

Подробнее

Во-первых, меня смущает эта заметка. Не используйте эту функцию на веб-сайте Microsoft о FMTONLY. Разве это не та же команда (с опцией ON) вызывается программой обновления модели EF? Это означает, что средство обновления модели EF использует функцию, которую не следует использовать.

Во-вторых, я предполагаю, что это поведение средства обновления модели EF направлено на предотвращение нежелательных манипуляций с данными БД, когда хранимая процедура выполняется со всеми входными аргументами, равными NULL. Но реальное поведение не соответствовало этому предположению.

Рассмотрим простую хранимую процедуру ниже, где я пытался избежать использования SET FMTONLY OFF. Я проанализировал точное поведение с помощью профилировщика SQL при обновлении модели EF из Visual Studio (2013, CU 5, Pro).

SET NOCOUNT ON;

IF (1=0) --FOR EF edmx update this will actually execute
BEGIN
    DECLARE @tempTable TABLE
                       (
                           [id] [int], 
                           [date_local] [datetime2](7), 
                           [value] [float] NULL
                       )

    SELECT * FROM @tempTable
    RETURN 0
END

CREATE TABLE #TempValue
(
    [id] [int] NOT NULL,
    [date_local] [datetime2](7) NOT NULL,
    [value] [float] NULL

    CONSTRAINT [PK_TempValue] 
        PRIMARY KEY CLUSTERED ([id] ASC, [date_local] ASC)
                    WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                          ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]

INSERT INTO #TempValue (id, date_local, value)
    SELECT @id, *
    FROM OPENJSON(@valueJson)
    WITH (
          date_local datetime2(7) '$.dateTime',
          value float '$.value'
         );

SELECT * FROM #TempValue

Точки:

  1. Программа обновления модели EF называет это, входит внутрь IF (1=0) (как и ожидалось с SET FMTONLY ON) и работает SELECT * from @tempTable правильно.

  2. Игнорирует return 0 и продолжает выполнение остальной части тела хранимой процедуры.

  3. Он пропускает CREATE TABLE #TempValue но потом пытается бежать INSERT INTO #TempValue который, конечно, не существует, поэтому он останавливается здесь и не выполняет SELECT * FROM #TempValue, который также потерпит неудачу.

В этом случае сложный тип был сгенерирован правильно, потому что последний успешный выбор был SELECT * from @tempTable. Но я считаю, что это просто удача, потому что нет никаких последующих выборок, которые действительно выполняются. Для меня все это поведение ошибочно, в частности пропуск return 0 и CREATE TABLE #TempValue но затем позволяя INSERT INTO; если вы позволите INSERT INTO неужели вы не сохраняете данные БД?

Итак, мы попробовали два обходных пути, которые на самом деле работают:

  1. Положить SET FMTONLY OFFнаверху. Это работает, но меня это немного беспокоит. Не используйте эту функцию на веб-сайте Microsoft.

  2. Закомментируйте все тело SP и добавьте DECLARE @tempTable table ... SELECT * from @tempTableкак в примере выше. После обновления модели EF удалите добавленный фрагмент и раскомментируйте исходный код. Делайте это каждый раз при обновлении модели EF, так что это не очень эффективно.

Какой правильный и рекомендуемый способ сделать это?

0 ответов

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