【问题标题】:Why can't Entity Framework see my Stored Procedure's column information?为什么 Entity Framework 看不到我的存储过程的列信息?
【发布时间】:2021-12-13 16:12:10
【问题描述】:

我有以下存储过程,当我尝试函数导入时,它说我的存储过程不返回任何列。我错过了什么?有什么建议么?

过程:

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

【问题讨论】:

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


【解决方案1】:

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

SET FMTONLY OFF

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

【讨论】:

【解决方案2】:

幕后发生了什么?

  1. 在执行函数导入时 -> 获取列信息 ... Visual Studio 执行存储的过程,所有参数值为 NULL(您可以通过 MS SQL Profiler 进行交叉检查)。

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

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

在您的情况下,存储的 proc 参数不可为空,因此 Visual Studio 调用失败并且不返回任何列。

如何处理?

如果 (1=0) 开始 设置 FMTONLY 关闭 如果@param1 为空且@param2 为空,则 开始 选择 cast(null as varchar(10)) as Column1, cast(null as bit) 作为 Column2, cast(null as decimal) as Column3 结尾 结尾

准确地说(在你的情况下):

如果 (1=0) 开始 设置 FMTONLY 关闭 如果@SearchString 为空,那么 开始 选择 cast(null as int) 作为 ID, cast(null as varchar(255)) as VendorName, cast(null as varchar(255)) as ItemName, cast(null as varchar(2)) as Type 结尾 结尾

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

【讨论】:

  • 感谢您的提示!第一个问题:为什么需要if @SearchString is null then?如果我理解正确,您只需要在开头使用IF (1=0) 即可防止执行(始终为假)并允许列扫描。在我的情况下,它在没有空检查的情况下工作。
  • 使用 NULL 参数执行的存储过程的信息是黄金!使用 VS 将我的应用程序移植到新环境时,我有一个丢失的表,导致存储过程在 EF 尝试调用它以获取列值以构建复杂类型时静默失败。您的回答使我进入 SSMS 中的新查询窗口并使用 null 输入参数执行存储的 proc,复制帽子 EF 所做的,从而发现我的愚蠢错误,EF 默默地吞下了。
【解决方案3】:

为了完整和简化@benshabatnoam 的答案,只需将以下代码放在开头:

IF (1=2)
    SET FMTONLY OFF

注意:它适用于 EF 6.1.3 和 Visual Studio 2015 Update 3

【讨论】:

    【解决方案4】:

    如果您使用的是临时表,实体 (EDMX) 无法理解发生了什么。

    所以返回带有列名的空结果,注释掉所有存储过程并在 sql 管理器中执行,然后在 Visual Studio 中获取复杂类型。保存后,将存储过程恢复为原始状态(即未注释)。

    祝你好运/

    【讨论】:

      【解决方案5】:

      由于临时表,您遇到了这个问题。

      您需要做的就是:

      1. 更改存储过程以返回不带临时表的 select 语句。
      2. 进入函数导入,获取列信息。
      3. 将您的存储过程改回原来的。

      【讨论】:

        【解决方案6】:

        我想在 Sudhanshu Singh 的回答中添加一些内容:它工作得很好,但如果您有更复杂的结构,请将其与表声明结合起来。

        我已成功使用以下内容(将其放在存储过程的最开始):

        CREATE PROCEDURE [dbo].[MyStoredProc] 
        AS
        BEGIN
        
        SET NOCOUNT ON;
        
        IF (1=0) -- it never gets executed, but the EF deducts the structure from it
        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 模型浏览器。在模型浏览器中,找到您的存储过程,打开“Edit Function Import”对话框,选择“Returns a collection of ... Complex”,然后单击“Get Column Information”按钮。

        它应该显示上面定义的结构。如果是,请单击“创建新的复杂类型”,它将使用存储过程的名称创建一个,例如“MyStoredProc_Result”(附加“_Result”)。

        现在您可以在同一对话框的“返回...复杂的集合”的组合框中选择它。

        当您需要更新某些内容时,请先更新 SP,然后您可以返回“编辑函数导入”对话框并单击“更新”按钮(您无需从头开始重新创建所有内容)。

        【讨论】:

        • 这个方法对我有用,而普通的 select 语句没有。我的问题实际上是 EF 将不可为空的位列转换为bool?。我在我的表变量中添加了 not null & default 约束,它起作用了。我还必须删除旧的复杂类型实体才能真正重新生成新实体。
        【解决方案7】:

        作为一种让 EF 查找列的快速而肮脏的方法,注释掉存储过程中的 where 子句(可能添加一个 TOP 1 以阻止它返回所有内容),将 proc 添加到 EF 并创建复杂类型,然后再次取消注释 where 子句。

        【讨论】:

          【解决方案8】:

          我遇到了这个问题,我要做的是创建一个用户定义的表类型并返回它。

          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
          

          【讨论】:

            【解决方案9】:

            只需添加不带引号的选择语句,执行存储过程,获取更新模型,编辑函数导入并获取列信息。这应该填充新列。更新结果集并返回到您的存储过程并删除您刚刚添加的选择列表。并执行存储过程。这样,您的列将填充到结果集中。 请参阅下面在何处添加不带引号的选择列表。

                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'
            

            执行(@SQL)

            选择 ID、供应商名称、项目名称、类型 FROM #T

            我希望这对那里的人有所帮助。

            【讨论】:

              【解决方案10】:

              这是唯一正确的答案,可以从这里找到

              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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-04-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多