web-dev-qa-db-ja.com

EF4-選択したストアドプロシージャは列を返しません

いくつかの動的SQLでいくつかのリンクサーバーを呼び出すストアドプロシージャにクエリがあります。 EFはそれが気に入らないことを理解しているため、返されるすべての列を具体的にリストしました。それでも、それはまだ好きではありません。ここで何が間違っていますか?必要なクラスを作成できるように、EFがストアドプロシージャから返された列を検出できるようにするだけです。

ストアドプロシージャの最後の行を構成する次のコードを参照してください。

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
60
cjbarth

EFは、以下から結果セットを構築するストアドプロシージャのインポートをサポートしていません。

  • 動的クエリ
  • 一時テーブル

理由は、プロシージャをインポートするためですEFはそれを実行する必要があります。このような操作は、データベースの一部の変更をトリガーする可能性があるため危険です。そのため、EFはストアドプロシージャを実行する前に特別なSQLコマンドを使用します。

SET FMTONLY ON

このコマンドを実行すると、ストアドプロシージャは結果セットの列に関する「メタデータ」のみを返し、ロジックを実行しません。ただし、ロジックは実行されなかったため、一時テーブル(または構築された動的クエリ)はないため、メタデータには何も含まれていません。

次の2つの選択肢があります(これらの機能を使用しないためにストアドプロシージャを書き直す必要がある場合を除く)。

  • 返された複合型を手動で定義します(動作するはずです)
  • ハックを使用し、その先頭に置かれたストアドプロシージャを追加するためだけにSET FMTONLY OFF。これにより、SPの残りのコードを通常の方法で実行できます。インポート中にこれらの変更が実行されるため、SPはデータを変更しないことを確認してください!インポートが成功したら、そのハックを削除します。
145
Ladislav Mrnka

この非論理的なコードブロックを追加することで問題は解決しました。決してヒットしませんが

IF 1=0 BEGIN
    SET FMTONLY OFF
END

入力したデータセットが一時テーブルを好まないのはなぜですか

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

または、ユーザー定義のテーブルタイプを作成して返すことができます。

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は返された列の型を認識できるはずです。

12

他の一部が指摘しているように、手順が実際に実行されることを確認してください。特に、私の場合、管理者権限でログインしたことを完全に忘れて、SQL Server Management Studioでエラーなしで問題なくプロシージャを実行していました。アプリケーションのプリンシパルユーザーを使用してプロシージャを実行しようとすると、クエリにテーブルがあり、そのユーザーにはアクセス許可がありませんでした。

2
Chris Matthews

@tmanthleyが言ったことに加えて、SSMSで最初に実行して、ストアドプロシージャが実際に機能することを確認してください。いくつかのストアドプロシージャをインポートし、いくつかの依存するスカラー関数を忘れたため、EFはプロシージャが列を返さないと判断しました。私が以前に見つけたはずの間違いのように思えますが、その場合EFはエラーメッセージを表示しません。

1
Derreck Dean

私が追加するものは:

ストアドプロシージャにパラメーターがあり、既定のパラメーター値の結果セットが返されない場合、インポートも失敗します。

私のストアドプロシージャには2つの浮動小数点パラメーターがあり、両方のパラメーターが0の場合は何も返しません。

したがって、このストアドプロシージャをエンティティモデルに追加するには、これらのパラメータの値をストアドプロシージャに設定して、パラメータが実際に何であるかに関係なく、いくつかの行を返すようにします。

次に、このストアドプロシージャをエンティティモデルに追加した後、変更を元に戻しました。

1
tmanthey

両方の解決策:1-返された複合型を手動で定義します(動作するはずです)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

ありがとう

1
Ahmed Mostafa

興味深い副注:一時テーブルではなくテーブル変数を使用して最初に解決したのと同じ問題がありました(インポートのみ)。それは私にとって特に直感的ではありませんでした。最初に私の2つのSProcを観察したとき、私は気を失いました。

(SET FMTONLY OFFは私には役に立たなかったので、ちょうどFYIとしてEF側のハックに煩わされるのではなく、列情報を取得するために一時的にSProcsを変更しました。)

私の最善のオプションは、実際には、単に手動で複合型を作成し、関数インポートをそれにマッピングすることでした。うまく機能し、唯一の違いは、プロパティを作成するための追加のFactoryMethodがDesignerに含まれていたことです。

1
user1076406
SET FMTONLY OFF 

いずれかの手順で私のために働いたが、他の手順では失敗した。手順に従うことで問題を解決できます

  1. ストアドプロシージャ内で、同じ列タイプの一時テーブルを作成し、動的クエリによって返されたすべてのデータを一時テーブルに挿入しました。一時テーブルのデータを選択しました。

    Create table #temp
    (
       -- columns with same types as dynamic query    
    )
    
    EXEC sp_executeSQL @sql 
    
    insert into #temp 
        Select * from #temp 
    
    drop table #temp
    
  2. 古いストアドプロシージャの既存の複合型、インポート関数、ストアドプロシージャインスタンスを削除し、現在の新しいプロシージャのエンティティモデルを更新しました。

  3. 目的の複合型のエンティティモーダルでインポートされた関数を編集すると、以前のストアドプロシージャでは取得できない列情報がすべて取得されます。

  4. 型の作成が完了したら、ストアドプロシージャから一時テーブルを削除して、Entity Frameworkを更新できます。

0
PVIJAY

Entityフレームワークでは、列情報を取得している間に、sqlはパラメーターにnull値を渡してプロシージャを実行します。そのため、必要なすべての列を含む一時テーブルを作成し、プロシージャにnullが渡されたときに値のないすべての列を返すことで、nullケースを異なる方法で処理しました。

私の手順では、次のような動的クエリがありました

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トリックを使用した後、私の場合は列情報を取得していませんでした。

これは、空のデータを取得するために作成した一時テーブルです。今、私は列情報を取得しています

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

Entity Frameworkは、ストアドプロシージャを実行し、すべての引数にNULLを渡すことで列を取得しようとします。

  1. ストアドプロシージャがすべての状況で何かを返すことを確認してください。 NULLではなく、Entity Frameworkが引数のデフォルト値を使用してストアドプロシージャを実行する方が賢い場合があることに注意してください。

  2. ERは、テーブルのメタデータを取得するために次のことを行います。

    FMTONLY ONを設定

  3. これにより、特に一時テーブルを使用する場合など、さまざまな状況でストアドプロシージャが破損します。

  4. したがって、結果を複合型として取得するには、追加してみてください

    FMTONLY OFFに設定します。

これは私のために働いた-それもあなたのために働くことを願っています。

参照元 https://social.msdn.Microsoft.com/Forums/en-US/e7f598a2-6827-4b27-a09d-aefe733b48e6/entity-model-add-function-import-stored-procedure-returns- no-columns?forum = adodotnetentityframework

0
Kiran Nandan

私の場合、SET FMTONLY OFFは機能しませんでした。私が従った方法は、元のストアドプロシージャのバックアップを取り、以下のクエリのように列名のみで置き換えることです。

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

この変更後、エンティティフレームワークに新しい関数インポート、複合型を作成します。関数インポートと複合型が作成されたら、上記のクエリを元のストアドプロシージャに置き換えます。

0
Darshan Jadyal

私の場合、プロシージャの先頭にSET NOCOUNT ON;を追加すると問題が修正されました。とにかくベストプラクティスです。

0
Endrju