我有以下存储过程,当我尝试使用Function Import时,我的存储过程不会返回任何列。我错过了什么?有什么建议?
The Proc:
ALTER PROCEDURE [healthc].[ev_kc_Products_Search]
(
@SearchString VARCHAR(1000)
)
AS
SET NOCOUNT ON
DECLARE @SQL VARCHAR(max),
@SQL1 VARCHAR(max),
@Tag VARCHAR(5)
CREATE TABLE #T
( ID INT,
VendorName VARCHAR(255),
ItemName VARCHAR(255),
Type VARCHAR(2),
Sequence TINYINT
)
SET @SQL = '
INSERT #T
SELECT VendorID ID,
Name VendorName,
NULL ItemName,
''V'' Type,
0 Sequence
FROM tblVendors
WHERE '+REPLACE(@SQL1,@Tag,'Name')+'
UNION ALL
BLAH BLAH BLAH'
EXEC(@SQL)
SELECT ID, VendorName, ItemName, Type FROM #T
答案 0 :(得分:50)
尝试将此行添加到存储过程的开头:
SET FMTONLY OFF
您可以在导入完成后将其删除。
答案 1 :(得分:35)
幕后发生什么事?
执行功能导入时 - >获取列信息... Visual Studio以所有param值为NULL执行存储过程(您可以通过MS SQL Profiler对此进行交叉检查)。
执行步骤1,返回存储过程的结果列及其数据类型和长度信息。
获取列信息后,单击“创建新的复杂类型”按钮可在争用中创建SP的复杂类型。
在您的情况下,存储的proc参数不可为空,因此Visual Studio调用失败并且不返回任何列。
如何处理?
IF (1=0) BEGIN SET FMTONLY OFF if @param1 is null and @param2 is null then begin select cast(null as varchar(10)) as Column1, cast(null as bit) as Column2, cast(null as decimal) as Column3 END END
准确地说(在你的情况下):
IF (1=0) BEGIN SET FMTONLY OFF if @SearchString is null then BEGIN select cast(null as int) as ID, cast(null as varchar(255)) as VendorName, cast(null as varchar(255)) as ItemName, cast(null as varchar(2)) as Type END END
答案 2 :(得分:6)
在完整性和简单的@benshabatnoam回答中,只需将以下代码放在开头:
IF (1=2)
SET FMTONLY OFF
注意:它适用于EF 6.1.3和Visual Studio 2015 Update 3
答案 3 :(得分:3)
由于临时表,您遇到此问题。 你需要做的就是: 1.更改存储过程以返回没有临时表的select statemant。 2.转到函数import并获取列信息。 3.将存储过程更改回原始文件。
答案 4 :(得分:2)
如果您使用临时表,实体(EDMX)无法理解发生了什么。
因此,使用列名返回空结果,注释掉所有存储过程并在sql管理器中执行,然后在visual studio中获取复杂类型。保存后,将存储过程返回到其原始状态(取消注释)。
祝你好运答案 5 :(得分:1)
作为一种快速而又脏的方法,使EF找到列,注释掉存储过程中的where子句(可能添加TOP 1以阻止它返回所有内容),将proc添加到EF并创建复杂类型,然后再次取消注释where子句。
答案 6 :(得分:1)
我想在Sudhanshu Singh的回答中添加一些内容:它的效果很好,但是如果你有更复杂的结构,请将它与表声明结合起来。
我已成功使用以下内容(将其置于存储过程的最开头):
CREATE PROCEDURE [EY].[MyStoredProc]
AS
BEGIN
SET NOCOUNT ON;
IF (1=0)
BEGIN
SET FMTONLY OFF
BEGIN
-- declaration + dummy query
-- to allow EF obtain complex data type:
DECLARE @MyStoredProcResult TABLE(
ID INT,
VendorName VARCHAR(255),
ItemName VARCHAR(255),
Type VARCHAR(2),
Sequence TINYINT
);
SELECT * FROM @MyStoredProcResult WHERE (1=0)
END
END
-- your code follows here (SELECT ... FROM ...)
-- this code must return the same columns/data types
--
-- if you require a temp table / table variable like the one above
-- anyway, add the results during processing to @MyStoredProcResult
-- and then your last statement in the SP can be
-- SELECT * FROM @MyStoredProcResult
END
注意 1=0
保证永远不会执行,但EF会从中扣除结构。
保存存储过程后,在Visual Studio中打开EDMX文件,刷新数据模型,转到Entity Frameworks模型浏览器。在模型浏览器中,找到存储过程,打开“编辑功能导入”对话框,选择“返回...复杂的集合”,然后单击“获取列信息”按钮。
它应该显示如上定义的结构。如果是,请单击“创建新的复杂类型”,它将创建一个具有存储过程名称的文件,例如, “MyStoredProc_Result”(附加“_Result”)。
现在,您可以在同一个对话框的“返回......复杂的集合”的组合框中选择它。
每当您需要更新某些内容时,首先更新SP,然后您可以返回编辑功能导入对话框并单击“更新”按钮(您无需从头开始重新创建所有内容)。 / p>
答案 7 :(得分:0)
我有这个问题,我必须做的是创建一个用户定义的表类型并返回它。
CREATE TYPE T1 AS TABLE
( ID INT,
VendorName VARCHAR(255),
ItemName VARCHAR(255),
Type VARCHAR(2),
Sequence TINYINT
);
GO
您的存储过程现在看起来像这样:
ALTER PROCEDURE [healthc].[ev_kc_Products_Search]
(
@SearchString VARCHAR(1000)
)
AS
SET NOCOUNT ON
DECLARE @SQL VARCHAR(max),
@SQL1 VARCHAR(max),
@Tag VARCHAR(5)
@T [schema].T1
SET @SQL = 'SELECT VendorID ID,
Name VendorName,
NULL ItemName,
''V'' Type,
0 Sequence
FROM tblVendors
WHERE '+REPLACE(@SQL1,@Tag,'Name')+'
UNION ALL
BLAH BLAH BLAH'
INSERT INTO @T
EXEC(@SQL)
SELECT ID, VendorName, ItemName, Type FROM @T
答案 8 :(得分:0)
只需添加不带引号的select语句,执行存储过程,获取更新模型,编辑函数导入并获取列信息。这应该填充新列。更新结果集并返回到存储过程并删除刚刚添加的选择列表。并执行存储过程。这样,您的列将填充到结果集中。 请参阅下面添加没有引号的选择列表的位置。
ALTER PROCEDURE [healthc].[ev_kc_Products_Search]
(
@SearchString VARCHAR(1000)
)
AS
SET NOCOUNT ON;
SELECT VendorID ID,
Name VendorName,
NULL ItemName,
''V'' Type,
0 Sequence
FROM tblVendors
DECLARE @SQL VARCHAR(max),
@SQL1 VARCHAR(max),
@Tag VARCHAR(5)
CREATE TABLE #T
( ID INT,
VendorName VARCHAR(255),
ItemName VARCHAR(255),
Type VARCHAR(2),
Sequence TINYINT
)
SET @SQL ='
INSERT #T
SELECT VendorID ID,
Name VendorName,
NULL ItemName,
''V'' Type,
0 Sequence
FROM tblVendors
WHERE '+REPLACE(@SQL1,@Tag,'Name')+'
UNION ALL
BLAH BLAH BLAH'
EXEC(@SQL)
SELECT ID,VendorName,ItemName,Type FROM #T
我希望这可以帮助那些人。
答案 9 :(得分:0)
这是唯一正确的答案,可以在这里找到
https://stackoverflow.com/a/27960583/511273
基本上,EF知道总是会返回行数,如果-1
为开,则返回NO COUNT
,或者返回由return <some integer>
调用的SQL存储过程返回的任何内容。因此,无论您导入哪种存储过程,类型都将始终为nullable<int>
。您只能从SQL存储过程返回整数。因此,EF为您提供了一种编辑功能的方法。我想如果您手动编辑它,则刷新后会覆盖它,但我无法确认。无论哪种方式,这都是EF提供的用于解决此问题的工具。
点击您的.emdx
文件。它必须是您在Solution Explorer
中选择的那个。选择Model Browser
(位于Solution Explorer
上方Properties
标签旁边)。展开Function Imports
,找到您的存储过程,右键单击,单击Edit
。选择变量类型。它可以是原始类型,也可以单击Get Complex Type
。点击Get Column Information
。我确认这可以在模型刷新后保留。
为什么只从存储过程返回整数?我不太清楚,但是此返回定义说明您只能返回整数: https://docs.microsoft.com/en-us/sql/t-sql/language-elements/return-transact-sql?view=sql-server-ver15