概括
在我们的应用程序中,我们使用 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指出:请勿使用此功能。所以我想知道推荐的方法是导入存储过程并正确生成复杂类型。
更多细节
首先,我被这个注释弄糊涂了,不要在微软网站上使用这个关于FMTONLY
. 这不是ON
EF 模型更新程序调用的相同命令(带有选项)吗?这意味着 EF 模型更新程序使用了不应使用的功能。
其次,我假设此 EF 模型更新程序行为旨在防止在使用所有输入参数 equal 执行存储过程时进行不必要的 DB 数据操作NULL
。但实际行为似乎与这个假设不一致。
考虑下面一个简单的存储过程,我试图避免使用SET FMTONLY OFF
. 在从 Visual Studio(2013,CU 5,Pro)更新 EF 模型时,我使用 SQL 分析器分析了确切的行为。
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
要点:
EF 模型更新程序调用它,进入内部
IF (1=0)
(如预期的那样SET FMTONLY ON
),并SELECT * from @tempTable
正确运行。它忽略
return 0
并继续运行存储过程主体的其余部分。它跳过
CREATE TABLE #TempValue
但随后尝试运行INSERT INTO #TempValue
当然不存在的,所以它在这里停止并且不执行SELECT * FROM #TempValue
,这也会失败。
在这种情况下,复杂类型被正确生成,因为最后一次成功的选择是SELECT * from @tempTable
. 但我觉得这只是运气,因为没有实际运行的后续选择。对我来说,这整个行为是有缺陷的,特别是跳过return 0
然后CREATE TABLE #TempValue
允许INSERT INTO
;如果您确定允许INSERT INTO
您不保留数据库数据?
因此,我们尝试过的两种实际可行的解决方法如下:
放在
SET FMTONLY OFF
上面。它有效,但我对此有点担心不要在 Microsoft 网站上使用此功能。注释掉整个 SP 正文并
DECLARE @tempTable table ... SELECT * from @tempTable
按照上面的示例添加。更新 EF 模型后,删除添加的块并取消注释原始代码。每次更新 EF 模型时都执行此操作,因此效率不高。
什么是正确且推荐的方法?