web-dev-qa-db-ja.com

EFは、#tempテーブルから選択したストアドプロシージャから戻りスキーマを推測できません

以下を想定してください:

CREATE PROCEDURE [MySPROC]
AS 
BEGIN

CREATE TABLE #tempSubset(
    [MyPrimaryKey] [bigint]  NOT NULL,
    [OtherColumn]  [int]     NOT NULL)

INSERT INTO #tempSubset (MyPrimaryKey, OtherColumn) 
    SELECT SomePrimaryKey, SomeColumn 
    FROM   SomeHugeTable
    WHERE  LimitingCondition = true

SELECT MyPrimaryKey, OtherColumn 
FROM   #tempSubset
WHERE  SomeExpensiveCondition = true

END

関数のインポートを生成するか、戻り値の型をマップすると、EFは複雑な型を生成しないか、次のように通知します。

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

これを克服する方法は?

テーブル変数を使用 (パフォーマンス上の理由でこれを行わない) リターンスキーマを偽造し、実際のストアドプロシージャをコメントアウトする 、他の提案 同様のことを行うwith views ...しかし、不必要なオーバーヘッドを追加したり、モデルを更新するためにストアドプロシージャを壊す必要なく、これを行う方法が必要ですか?

37
JoeBrockhaus
CREATE PROCEDURE [MySPROC]
AS 
BEGIN

--supplying a data contract
IF 1 = 2 BEGIN
    SELECT
        cast(null as bigint)  as MyPrimaryKey,
        cast(null as int)    as OtherColumn
    WHERE
        1 = 2  
END

CREATE TABLE #tempSubset(
    [MyPrimaryKey] [bigint]  NOT NULL,
    [OtherColumn]  [int]     NOT NULL)

INSERT INTO #tempSubset (MyPrimaryKey, OtherColumn) 
    SELECT SomePrimaryKey, SomeColumn 
    FROM   SomeHugeTable
    WHERE  LimitingCondition = true

SELECT MyPrimaryKey, OtherColumn 
FROM   #tempSubset
WHERE  SomeExpensiveCondition = true

END

結果セットの偽データコントラクトを提供することが、問題を処理する最も簡単で、クリーンで、最速の方法です。この同じ問題は、SSISのデータソースコントロールにも存在します。 .NETは、クエリの到達不能な「契約」セクションから結果セットを読み取り、複合型のメタデータを提供します。パフォーマンスへの影響はなく、実際の作業を行うSQLをコメント化する必要もありません。

60
BrianKrahenbuhl

これをストアドプロシージャ定義の先頭に追加します。

SET FMTONLY OFF

例:

SET FMTONLY OFF

CREATE TABLE #tempTable (
    ...
)

...

SELECT * FROM #tempTable 
47

解決策1一時テーブルの代わりにテーブル変数を使用します。

解決策2 Set FMTONLY off;プロシージャ内のSQLコマンドを実行すると、列情報を取得して新しい複合型を作成します。

解決策3これは良い方法ではありませんが、非常に簡単な方法です。ダミーデータを含むselectステートメントを追加すると、1 = 0であるため実行されません。

このリンク で詳細を確認できます

10
user3364545

これは不完全ですが、set fmtonly offが機能しない場合、次を使用してデータコントラクトを生成できます。

        SELECT * 
        FROM tempdb.sys.columns 
        WHERE [object_id] = OBJECT_ID(N'tempdb..#u');

        select case  system_type_id 
        when 62 then 'cast(null as float) as ' 
        when 175 then 'cast(null as char(' + cast(max_length as varchar(50)) + ')) as ' 
        when 167 then 'cast(null as varchar(' + cast(max_length as varchar(50)) + ')) as ' 
        when 56 then 'cast(null as int) as ' 
        when 104 then 'cast(null as bit) as ' 
        when 106 then 'cast(null as decimal(' + cast(precision as varchar(50)) + ',' + cast(scale as varchar(50)) + ')) as ' 
        when 40 then 'cast(null as date) as '            
        end
        + name + ','
        from  tempdb.sys.columns 
        WHERE [object_id] = OBJECT_ID(N'tempdb..#u');
0
Mark Pearson