none
LINQ(C#)からのストアドプロシージャの実行 RRS feed

  • 質問

  • 簡単なテーブルを作成し、下記のストアドプロシージャを作りました。

    CREATE PROCEDURE [dbo].[test]

    AS

     SELECT *  FROM main_Table

    RETURN 0

    Management Studioだと正常に実行されて、結果がテーブルとして表示されるのですが、LINQ to SQLで下記のコードを作成して実行すると

                            LINQ_DBDataContext DB = new LINQ_DBDataContext();

                            var sqldata = (DB.test()).ToArray();
                            DB.Dispose();

    「クエリ結果を複数回列挙できません」とのエラーが出てしまいます。

    使用している環境はMicrosoft SQL Server 2014 Express です。無償版による制限が原因でしょうか?

    2018年4月19日 2:08

回答

  • 「RETURN 0」は受け取らず、「main_Table の内容」だけ得られればよいのですよね。

    手元に VS2015 が無かった(2012 と 2017 ならある)ので環境は異なりますが、当方では下記の結果になりました。
    VS2012/VS2017 共に同じ結果です。(なお、2017 は Linq to SQL をサポートしていないようだったので、VS2012 で作成したソリューションを VS2017 に読み込ませて実行しました)

    var sqldata1 = DB.test().ToArray(); // OK
    var sqldata2 = (DB.test()).ToArray(); // OK
    var sqldata3 = DB.test();
    var sqldata4 = sqldata3.ToArray(); // OK
    var sqldata5 = sqldata3.ToArray(); //『クエリ結果は複数回列挙できません。』

    sqldata5 が失敗するのは分かるのですが、今回は sqldata2 の構文が失敗するのですよね…。
    そちらの環境では、sqldata1 の構文でも失敗するのでしょうか?

    sqldata1 の構文であれば呼び出させるのであれば、"Roslyn" などによって、デバッグ時に括弧の内部が再評価されており、結果として sqldata5 相当の状態に陥っているのかもしれません。

    もしかしたら [デバッグ]-[ウィンドウ]から表示されるペインの「自動変数」「ウォッチ」「ローカル」を閉じておくと、再評価を防げるかも?(VS2015 を持ち合わせていないので確証は持てませんが)

    列挙後に再評価できない仕様ではあるようなので、追加検証として GetEnumerator でも試してみました。参考までに。

    var sqldata0 = DB.test();
    var x = sqldata0.GetEnumerator();
    var data1 = x.MoveNext() ? x.Current : null;  // 先1 行目のデータ
    var y = sqldata0.GetEnumerator(); //『クエリ結果は複数回列挙できません。』
    var data2 = y.MoveNext() ? x.Current : null;  // この行まで到達しない
    また、IEnumerator.Reset() は、呼び出しても特に効果がありませんでした。
    var sqldata0 = DB.test();
    var x = sqldata0.GetEnumerator();
    var data1 = x.MoveNext() ? x.Current : null;  // 1 行目のデータ
    x.Reset(); // この行は呼んでも呼ばなくても結果が変化しませんでした
    var data2 = x.MoveNext() ? x.Current : null;  // 1 行目ではなく 2 行目

    2018年4月19日 6:08

すべての返信

  • あなたの開発環境(OS, .NET, Visual Studio, Entity Framework のバージョンなど)を書いてください。

    LINQ_DBDataContext はどのように作ったか書いてください。

    2018年4月19日 2:20
  • OSはWindows 7 64bit,

    Visual Studio 2015 Express for Web

    Framework 4.6になります。

    LINQ_DBDataContextはLinq To SQLのdbmlファイルのドラッグエリアに

    ストアドプロシージャをSQLオブジェクトブラウザからドラッグしました。(ログインはsa)

    2018年4月19日 2:23
  • また、SQL severをインストールしているのはWindows Server 2012 R2です。
    2018年4月19日 2:24
  • Entity Framework のバージョンは何ですか?

    Linq to SQL でなければならない理由があるのでしょうか? そうでなければ Linq to Entities にしませんか?

    Linq to SQL はこの先もう使われなくなる運命のようですので、興味を持って質問に答えてくれる人は少なそうですので。

    2018年4月19日 3:28
  • 「RETURN 0」は受け取らず、「main_Table の内容」だけ得られればよいのですよね。

    手元に VS2015 が無かった(2012 と 2017 ならある)ので環境は異なりますが、当方では下記の結果になりました。
    VS2012/VS2017 共に同じ結果です。(なお、2017 は Linq to SQL をサポートしていないようだったので、VS2012 で作成したソリューションを VS2017 に読み込ませて実行しました)

    var sqldata1 = DB.test().ToArray(); // OK
    var sqldata2 = (DB.test()).ToArray(); // OK
    var sqldata3 = DB.test();
    var sqldata4 = sqldata3.ToArray(); // OK
    var sqldata5 = sqldata3.ToArray(); //『クエリ結果は複数回列挙できません。』

    sqldata5 が失敗するのは分かるのですが、今回は sqldata2 の構文が失敗するのですよね…。
    そちらの環境では、sqldata1 の構文でも失敗するのでしょうか?

    sqldata1 の構文であれば呼び出させるのであれば、"Roslyn" などによって、デバッグ時に括弧の内部が再評価されており、結果として sqldata5 相当の状態に陥っているのかもしれません。

    もしかしたら [デバッグ]-[ウィンドウ]から表示されるペインの「自動変数」「ウォッチ」「ローカル」を閉じておくと、再評価を防げるかも?(VS2015 を持ち合わせていないので確証は持てませんが)

    列挙後に再評価できない仕様ではあるようなので、追加検証として GetEnumerator でも試してみました。参考までに。

    var sqldata0 = DB.test();
    var x = sqldata0.GetEnumerator();
    var data1 = x.MoveNext() ? x.Current : null;  // 先1 行目のデータ
    var y = sqldata0.GetEnumerator(); //『クエリ結果は複数回列挙できません。』
    var data2 = y.MoveNext() ? x.Current : null;  // この行まで到達しない
    また、IEnumerator.Reset() は、呼び出しても特に効果がありませんでした。
    var sqldata0 = DB.test();
    var x = sqldata0.GetEnumerator();
    var data1 = x.MoveNext() ? x.Current : null;  // 1 行目のデータ
    x.Reset(); // この行は呼んでも呼ばなくても結果が変化しませんでした
    var data2 = x.MoveNext() ? x.Current : null;  // 1 行目ではなく 2 行目

    2018年4月19日 6:08
  • ありがとうございます。

    こちらの環境では、sqldata1の状態で失敗します。

    2018年4月19日 7:59