web-dev-qa-db-ja.com

Entity Frameworkがストアドプロシージャの列情報を表示できないのはなぜですか?

次のストアドプロシージャがあり、Function Importを実行しようとすると、ストアドプロシージャが列を返さないと表示されます。何が欠けていますか?助言がありますか?

手続き:

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
32

ストアドプロシージャの先頭に次の行を追加してみてください:

SET FMTONLY OFF

インポートが完了したら、これを削除できます。

54
benshabatnoam

ここで舞台裏で何が起こっていますか?

  1. 関数のインポートの実行中->列情報の取得... Visual Studioは、すべてのパラメーター値をNULLとしてストアドプロシージャを実行します(MS SQLプロファイラーを使用してこれをクロスチェックできます)。

  2. 手順1を実行すると、ストアドプロシージャの結果の列が、データ型と長さ情報とともに返されます。

  3. 列情報が取得されたら、「新しい複合型の作成」ボタンをクリックすると、SPの複合型が競合します。

あなたの場合、ストアドプロシージャのパラメーターはnullにできないため、Visual Studioの呼び出しは失敗し、列は返されません。

これをどのように処理しますか?

 IF(1 = 0)
 BEGIN 
 SET FMTONLY OFF 
 @ param1がnullで@ param2がnullの場合
 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 
 @SearchStringがnullの場合、
 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 /

38
Sudhanshu Singh

完全に、単純な@benshabatnoam回答を作成するには、最初に次のコードを挿入します。

IF (1=2)
    SET FMTONLY OFF

注:EF 6.1.3およびVisual Studio 2015 Update 3で動作します

6
Mahmoud Moravej

一時テーブルが原因でこの問題が発生しています。必要なのは次のとおりです。1.ストアドプロシージャを変更して、一時テーブルなしで選択状態を返すようにします。 2.関数importに移動して、列情報を取得します。 3.ストアドプロシージャを元に戻します。

3
benshabatnoam

一時テーブルを使用している場合、エンティティ(EDMX)は何が起こっているのか理解できません。

したがって、列名で空の結果を返し、すべてのストアドプロシージャをコメントアウトしてSQLマネージャーで実行し、Visual Studioで複合型を取得します。保存後、ストアドプロシージャを元の状態(コメント化されていない状態)に戻します。

幸運を/

3
Ehud Grand

EFで列をすばやく簡単に見つける方法として、ストアドプロシージャのwhere句をコメント化し(TOP 1を追加してすべてを返さないようにする)、プロシージャをEFに追加して複合型を作成し、コメントを外します再びwhere句。

1
SteveCav

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"によって追加)。

同じダイアログの「Returns a collection of ... Complex」のコンボボックスで選択できるようになりました。

何かを更新する必要があるときはいつでも、SPを最初に更新してから、[関数インポートの編集]ダイアログに戻って[更新]ボタンをクリックできます(再作成する必要はありません)ゼロからすべて)。

1
Matt

これが唯一の正解であり、ここから見つけることができます

https://stackoverflow.com/a/27960583/51127

基本的に、EFは、行数または_-1_がオンの場合は_NO COUNT_、または_return <some integer>_によって呼び出されたSQLストアドプロシージャから返されるものは常に返されることを認識しています。そのため、どのストアドプロシージャをインポートしても、型は常に_nullable<int>_になります。 SQLストアドプロシージャからは整数のみを返すことができます。したがって、EFは関数を編集する方法を提供します。手動で編集した場合、更新時に上書きされると思いますが、確認できません。いずれにせよ、これはEFがこの問題に対処するために提供する機能です。

_.emdx_ファイルをクリックします。 _Solution Explorer_で選択したものである必要があります。 _Model Browser_を選択します(Propertiesの上にある_Solution Explorer_タブのすぐ横)。 _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

0
Bluebaron

この問題が発生したため、ユーザー定義のテーブルタイプを作成してそれを返す必要がありました。

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
0
Wesley Coetzee

引用符なしで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
)

セット@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
Yoky