web-dev-qa-db-ja.com

C#リーダーが閉じられているときにReadを呼び出す無効な試み

C#言語で3層プロジェクトを実行しているときに、リーダーが閉じられているときにReadを呼び出す無効な試行があります。私がやろうとしているのは、2つのテーブルを結合してドロップダウンリストに表示することにより、アドレスデータ列を取得することです。データアクセスレイヤーは次のとおりです。

    public List<Distribution> getDistributionAll()
    {
        List<Distribution> distributionAll = new List<Distribution>();
        string address;
        SqlDataReader dr = FoodBankDB.executeReader("SELECT b.addressLineOne FROM dbo.Beneficiaries b INNER JOIN dbo.Distributions d ON d.beneficiary = b.id");

        while (dr.Read())
        {
            address = dr["addressLineOne"].ToString();
            distributionAll.Add(new Distribution(address));
        }

        return distributionAll;
    }

そして、これは私のFoodBankDBクラスです:

   public class FoodBankDB
{
    public static string connectionString = Properties.Settings.Default.connectionString;
    public static SqlDataReader executeReader(string query)
    {
        SqlDataReader result = null;
        System.Diagnostics.Debug.WriteLine("FoodBankDB executeReader: " + query);
        SqlConnection connection = new SqlConnection(connectionString);
        SqlCommand command = new SqlCommand(query, connection);
        connection.Open();
        result = command.ExecuteReader();
        connection.Close();
        return result;
    }

接続文字列が変更されるたびに、FoodBankDBクラスを変更することでプロジェクト全体を簡単に修正できるように、これらを2つのクラスに分けました。

そして、これが私のビジネスロジックレイヤーです。

public List<Distribution> getAllScheduledDistribution()
    {
        List<Distribution> allDistribution = new List<Distribution>();
        Distribution distributionDAL = new Distribution();
        allDistribution = distributionDAL.getDistributionAll();
        return allDistribution;
    }

最後に、プレゼンテーションレイヤー:

List<Distribution> scheduledList = new List<Distribution>();
scheduledList = packBLL.getAllScheduledDistribution();
ddlScheduleList.DataSource = scheduledList;
ddlScheduleList.DataTextField = "address";
ddlScheduleList.DataValueField = "address";
ddlScheduleList.DataBind();

データアクセス層と接続文字列クラスを分割しなければ、うまく機能していました。誰もこのエラーを解決する方法を知っていますか?

前もって感謝します。

更新部分

        public static string GetConnectionString()
    {
        return connectionString;
    }
16
user2531590

リーダーを返す前に接続を閉じるため、機能しません。 Readerは、接続が開いている場合にのみ機能します。

result = command.ExecuteReader();
connection.Close();

return result; // here the reader is not valid

一般的に、読者をビジネス層に戻すべきではありません。 Readerは、データアクセス層でのみ使用する必要があります。それを使用してから、接続と接続を閉じる必要があります。

むしろ、接続が閉じられた後に機能するオブジェクトを返す必要があります。 DataSetまたはDataTable、あるいはDTOのコレクション。例えば:

public List<Distribution> getDistributionAll()
{
    List<Distribution> distributionAll = new List<Distribution>();

    using (var connection = new SqlConnection(FoodBankDB.GetConnectionString())) // get your connection string from the other class here
    {
        SqlCommand command = new SqlCommand("SELECT b.addressLineOne FROM dbo.Beneficiaries b INNER JOIN dbo.Distributions d ON d.beneficiary = b.id", connection);
        connection.Open();
        using (var dr = command.ExecuteReader())
        {
            while (dr.Read())
            {
                string address = dr["addressLineOne"].ToString();

                distributionAll.Add(new Distribution(address));
            }
        }
    }

    return distributionAll;
}
26
Szymon

前の例は良い例です...しかし、datareader.close()メソッドが呼び出されたときにautomaticallyインスタンスを閉じるconnectionであるコードによっても達成できます...

reader = Sqlcmd.ExecuteReader(CommandBehavior.CloseConnection); 
6
Moumit