为什么Entity Framework无法查看我的存储过程的列信息?

时间:2011-05-13 19:35:16

标签: entity-framework stored-procedures entity-framework-4

我有以下存储过程,当我尝试使用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

10 个答案:

答案 0 :(得分:50)

尝试将此行添加到存储过程的开头:

SET FMTONLY OFF

您可以在导入完成后将其删除。

答案 1 :(得分:35)

幕后发生什么事?

  1. 执行功能导入时 - >获取列信息... Visual Studio以所有param值为NULL执行存储过程(您可以通过MS SQL Profiler对此进行交叉检查)。

  2. 执行步骤1,返回存储过程的结果列及其数据类型和长度信息。

  3. 获取列信息后,单击“创建新的复杂类型”按钮可在争用中创建SP的复杂类型。

  4. 在您的情况下,存储的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   
    

    参考:http://mysoftwarenotes.wordpress.com/2011/11/04/entity-framework-4-%E2%80%93-the-selected-stored-procedure-returns-no-columns-part-2/

答案 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