2017-12-09 7 views
0

SQLストアドプロシージャを実行していて、いくつかのテーブル結果を送信しているサーバー側のコードです。IEnumerableの結果を返す関数を呼び出す方法は?

ここにFixNullParams関数があります。 、私はこのように、この関数を呼び出す

 private void FixNullParams(SqlParameter[] parameters) 
    { 
     foreach (SqlParameter p in parameters) if (p.Value == null) p.Value = DBNull.Value; 
    } 

   List<SqlParameter> parameters = new List<SqlParameter>(); 
      parameters.Add(new SqlParameter("@AgencyFilter", "CountyPool")); 
      IEnumerable<IDataRecord> dataFromDB = salesTax.SomeFuncToCallDB("[Data].[uspSomeSQLProc]", parameters.ToArray()); 

は、私は次の例外を取得します。

"SqlParameterは、すでに別のSqlParameterCollectionに含まれています。"

これはラインcmd.Parameters.AddRangeで起こります。

私は

List<SqlParameter> parameters = new List<SqlParameter>(); 
      parameters.Add(new SqlParameter("@AgencyFilter", "CountyPool")); 
      //IEnumerable<IDataRecord> dataFromDB = salesTax.SomeFuncToCallDB("[Data].[uspAgenciesSelect]", parameters.ToArray()); 
      foreach (IDataRecord eachRec in salesTax.SomeFuncToCallDB("[Data].[uspSomeSQLProc]", parameters.ToArray())) 
      { 
       int x = eachRec.FieldCount; 

      } 

、このように同じ関数を呼び出した場合は、同時に、そして、それが正常に働いて、各レコードをループ。

ここに私の質問があります。

  1. この手順をどのように呼び出すのが適切ですか?
  2. 後の呼び出しでどうして失敗しないのですが、元の呼び出しで失敗しますか?
  3. 私はこの機能のためのユニットテストを記述する必要がある場合、私はちょうどIEnumerableを取得し、レコード数を主張したいです。しかし、このような例外のために、私はこの種のテストを行うことはできません。では、この関数を単体テストするための正しい方法は何ですか?
+2

ここで 'parameters'はどこに作成しますか?すでに他の場所で既に使用されているパラメータを使用していると思われます。あなたの質問を明確にし、コードセクションを編集して、できるだけわかりやすくなるようにしてください。 –

+0

コンパイル時に、列挙可能なメソッドがステートマシンを生成します。私はあなたに細かい細部を伝えることはできませんが、それはそれと関係があると思います。誰かがそれを知っているなら、それはジョン・スケートです。 – Crowcoder

+0

@JonSkeet私はあなたが正しいと信じています、OPは問題が含まれている彼のコードの部分を記述していません、エラーがキャッチされた場所。 SQLパラメータクラスインスタンスの場所と使用方法を説明する必要があります。 OPがSQLパラメータを再利用しています。おそらく、あなたが使用している "FixNull"メソッドは、同じ "空の"パラメータを返すか、返すものでシステムを混乱させるでしょう。正直なところ、あなたが提供したコードでエラーの原因を特定することはできません。 –

答えて

0

私が思うには、私は問題を発見しました。 Visual Studio 2017のデバッグ動作です。

小さなテストデータベースを作成してから、この問題を再現する簡単なWindowsアプリケーションを作成できました。両方の呼び出しが同じように動作します。

しかし、私はラインデバッグ操作によってラインを実行すると、以下のスナップショットに示すように、この例外がでゾッと。好奇心旺盛なユーザーの場合

enter image description here

、私はここで完全なソースコードを追加しました。

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Data.SqlClient; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace Iterator 
{ 
public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      List<SqlParameter> parameters = new List<SqlParameter>(); 
      parameters.Add(new SqlParameter("@hobbyName", "Coding")); 
      IEnumerable<IDataRecord> dataFromDB = GetUserInfo("dbo.GetUserBasedOnHobby", parameters.ToArray()); 
      int totalCount = dataFromDB.Count(); 
      MessageBox.Show("Total count : " + totalCount.ToString()); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show("Error : " + ex.ToString()); 
     } 
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      List<SqlParameter> parameters = new List<SqlParameter>(); 
      parameters.Add(new SqlParameter("@hobbyName", "Coding")); 
      List<IDataRecord> allRecs = new List<IDataRecord>(); 
      foreach (IDataRecord eachRec in GetUserInfo("dbo.GetUserBasedOnHobby", parameters.ToArray())) 
      { 
       allRecs.Add(eachRec); 
      } 
      int totalCount = allRecs.Count(); 
      MessageBox.Show("Total count : " + totalCount.ToString()); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show("Error : " + ex.ToString()); 
     } 
    } 

    private void FixNullParams(SqlParameter[] parameters) 
    { 
     foreach (SqlParameter p in parameters) if (p.Value == null) p.Value = DBNull.Value; 
    } 

    public IEnumerable<IDataRecord> GetUserInfo(string pName, SqlParameter[] sqlParams, int commandTimeout = -1) 
    { 
     using (SqlConnection cn = new SqlConnection("Data Source=MACHINE2;Initial Catalog=TestDB;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False")) 
     using (SqlCommand cmd = cn.CreateCommand()) 
     { 
      cmd.CommandText = pName; 
      cmd.CommandType = CommandType.StoredProcedure; 
      if (commandTimeout != -1) cmd.CommandTimeout = commandTimeout; 
      if (sqlParams.Length > 0) 
      { 
       FixNullParams(sqlParams); 
       cmd.Parameters.AddRange(sqlParams); 
      } 
      cn.Open(); 
      using (SqlDataReader dr = cmd.ExecuteReader()) 
      { 
       while (dr.Read()) 
       { 
        yield return (IDataRecord)dr; 
       } 
       cn.Close(); 
      } 
     } 
    } 


    } 
} 

これはサンプルテストデータです。

enter image description here

これは、ストアドプロシージャのSQLスクリプトです。

USE [TestDB] 
GO 

/****** Object: StoredProcedure [dbo].[GetUserBasedOnHobby] Script Date: 12/9/2017 3:14:43 PM ******/ 
SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE PROCEDURE [dbo].[GetUserBasedOnHobby] 
@hobbyName varchar(50) 
    AS 
SELECT * from dbo.UserTable where dbo.UserTable.Hobby = @hobbyName; 
    RETURN 0 
    GO 

ご意見ありがとうございます。それは私が問題を発見するために深く掘り下げるのを助けました。

関連する問題