EF4 – 选定的存储过程不返回任何列

我有一个存储过程中的查询,调用一些dynamicSQL的一些链接的服务器。 我明白,EF不喜欢这样,所以我特别列出了所有将被返回的列。 然而,它仍然不是那样的。 我在这里做错了什么? 我只想EF能够检测从存储过程返回的列,所以我可以创build我需要的类。

请参阅构成我的存储过程的最后一行的以下代码:

SELECT #TempMain.ID, #TempMain.Class_Data, #TempMain.Web_Store_Class1, #TempMain.Web_Store_Class2, #TempMain.Web_Store_Status, #TempMain.Cur_1pc_Cat51_Price, #TempMain.Cur_1pc_Cat52_Price, #TempMain.Cur_1pc_Cat61_Price, #TempMain.Cur_1pc_Cat62_Price, #TempMain.Cur_1pc_Cat63_Price, #TempMain.Flat_Length, #TempMain.Flat_Width, #TempMain.Item_Height, #TempMain.Item_Weight, #TempMain.Um, #TempMain.Lead_Time_Code, #TempMain.Wp_Image_Nme, #TempMain.Wp_Mod_Dte, #TempMain.Catalog_Price_Chg_Dt, #TempMain.Description, #TempMain.Supersede_Ctl, #TempMain.Supersede_Pn, TempDesc.Cust_Desc, TempMfgr.Mfgr_Item_Nbr, TempMfgr.Mfgr_Name, TempMfgr.Vendor_ID FROM #TempMain LEFT JOIN TempDesc ON #TempMain.ID = TempDesc.ID LEFT JOIN TempMfgr ON #TempMain.ID = TempMfgr.ID 

EF不支持从以下版本导入构build结果集的存储过程:

  • dynamic查询
  • 临时表

原因是导入过程EF必须执行它 。 这样的操作可能是危险的,因为它可以触发数据库中的一些变化。 因为EF在执行存储过程之前使用特殊的SQL命令:

 SET FMTONLY ON 

通过执行这个命令,存储过程将只返回关于结果集中的列的“元数据”,而不会执行其逻辑。 但是由于逻辑没有被执行,所以没有临时表(或者构build的dynamic查询),所以元数据不包含任何内容。

您有两个select(除了需要重写存储过程而不使用这些function的选项):

  • 手动定义返回的复杂types(我想它应该工作)
  • 使用黑客,只是为了添加存储过程放在开始SET FMTONLY OFF 。 这将允许其余的SP代码以正常的方式执行。 只要确保你的SP不修改任何数据,因为这些修改将在导入过程中执行! 成功导入后,删除该黑客。

添加这个非逻辑代码块解决了这个问题。 即使它永远不会命中

 IF 1=0 BEGIN SET FMTONLY OFF END 

为什么我的types数据集不像临时表?

http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataset/thread/fe76d511-64a8-436d-9c16-6d09ecf436ea/

或者你可以创build一个用户定义的表types并返回。

 CREATE TYPE T1 AS TABLE ( ID bigint NOT NULL ,Field1 varchar(max) COLLATE Latin1_General_CI_AI NOT NULL ,Field2 bit NOT NULL ,Field3 varchar(500) NOT NULL ); GO 

然后在程序中:

 DECLARE @tempTable dbo.T1 INSERT @tempTable (ID, Field1, Field2, Field3) SELECT ..... .... SELECT * FROM @tempTable 

现在EF应该能够识别返回的列types。

正如其他人已经注意到的,确保程序实际运行。 特别是在我的情况下,我在SQL Server Management Studio中高兴地运行了程序,没有错误,完全忘记了我是用pipe理员权限login的。 只要我尝试运行使用我的应用程序的主要用户的程序,我发现在查询中有一个表,该用户没有权限访问。

我要补充的是:

如果存储过程具有参数并且不为默认参数值返回任何结果集,则导入也会失败。

我的存储过程有2个浮点参数,当两个参数都为0时,不会返回任何东西。

所以为了将这个存储过程添加到实体模型中,我在存储过程中设置了这些参数的值,以保证返回一些行,而不pipe实际参数是什么。

然后在将此存储过程添加到实体模型之后,我解开了更改。

有趣的一面是:有同样的问题,我首先使用表variables解决,而不是临时表(只为导入)。 这对我来说并不是特别直观,当我开始观察我的两个SProcs时,就把我扔了:一个使用Temp表,另一个使用Table Variables。

(SET FMTONLY OFF从来没有为我工作过,所以我只是暂时改变了我的SProcs来获得列信息,而不是像EFI那样只是简单的干预而已。)

我最好的select只是手动创build复杂types并将函数导入映射到它。 工作得很好,唯一的区别就是在Designer中包含了额外的FactoryMethod来创build属性。

两种解决scheme:1 – 手动定义返回的复杂types(我想它应该工作)2 – 使用黑客,只是添加存储过程放在其开始SET FMTONLY OFF。

在某些程序中没有和我一起工作,但是和其他程序一起工作!

我的程序以这一行结束:

 SELECT machineId, production [AProduction] , (select production FROM #ShiftBFinalProd WHERE machineId = #ShiftAFinalProd.machineId) [BProduction] , (select production FROM #ShiftCFinalProd WHERE machineId = #ShiftAFinalProd.machineId) [CProduction] FROM #ShiftAFinalProd ORDER BY machineId 

谢谢

除了@tmanthley所说的之外,还要确保你的存储过程在SSMS中首先运行它。 我导入了一些存储过程,并忘记了一些依赖于标量的函数,这导致EF确定该过程没有返回任何列。 看起来像我之前应该发现的一个错误,但EF在这种情况下不会给你一个错误信息。

在我的情况下添加SET NOCOUNT ON; 在程序的顶部解决了问题。 无论如何,这是最好的做法。

在我的情况下,SET FMTONLY OFF不起作用。 我遵循的方法是,我采取了原始存储过程的备份,并replace只有列名称,如下面的查询。

 Select Convert(max,'') as Id,Convert(max,'') as Name 

在这个改变之后,在entity framework中创build新的函数导入,复合types。 一旦创build了函数导入和复杂types,请将上述查询replace为原始存储过程。

 SET FMTONLY OFF 

为我的程序之一,但其他程序失败。 以下步骤帮助我解决我的问题

  1. 在存储过程中,我创build了具有相同列types的临时表,并将dynamic查询返回的所有数据都插入临时表中。 并select临时表数据。

     Create table #temp ( -- columns with same types as dynamic query ) EXEC sp_executeSQL @sql insert into #temp Select * from #temp drop table #temp 
  2. 删除旧存储过程的现有复杂types,导入function和存储过程实例以及当前新过程的更新实体模型。

  3. 在实体模式中编辑导入的函数以获取所需的复杂types,您将获得所有列信息,这些信息不会用于以前的存储过程。

  4. 一旦你完成了types创build,你可以从存储过程中删除临时表,然后刷新entity framework。

在entity framework中,在获取列信息的同时,sql在参数中传递null值来执行过程。 所以我通过创build一个具有所有必需列的临时表来处理空大小写情况,并在空值传递给过程时返回所有没有值的列。

在我的程序中有dynamic查询,类似

 declare @category_id int set @category_id = (SELECT CATEGORY_ID FROM CORE_USER where USER_ID = @USER_ID) declare @tableName varchar(15) declare @sql VARCHAR(max) declare @USER_IDT varchar(100) declare @SESSION_IDT varchar(10) IF (@category_id = 3) set @tableName = 'STUD_STUDENT' else if(@category_id = 4) set @tableName = 'STUD_GUARDIAN' if isnull(@tableName,'')<>'' begin set @sql = 'SELECT [USER_ID], [FIRST_NAME], SCHOOL_NAME, SOCIETY_NAME, SCHOOL_ID, SESSION_ID, [START_DATE], [END_DATE] from @tableName .... EXECUTE (@sql) END ELSE BEGIN SELECT * from #UserPrfTemp END 

在使用FMTONLY OFF技巧后,我没有收到我的案例中的列信息。

这是我创build的临时表以获取空白数据。 现在我正在获取列信息

 Create table #UserPrfTemp ( [USER_ID] bigint, [FIRST_NAME] nvarchar(60), SCHOOL_NAME nvarchar(60), SOCIETY_NAME nvarchar(200) ..... }