web-dev-qa-db-fra.com

C # Tentative non valide d'appeler Read lorsque le lecteur est fermé

J'ai une tentative non valide d'appeler Read lorsque le lecteur est fermé erreur lorsque je fais un projet à 3 niveaux en langage C #. Ce que j'essaie de faire est de récupérer la colonne des données d'adresse en joignant deux tables et de les afficher dans une liste déroulante. Voici ma couche d'accès aux données:

    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;
    }

Et voici ma classe 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;
    }

J'ai séparé ces derniers en deux classes de sorte que chaque fois que ma chaîne de connexion est modifiée, je peux facilement modifier l'ensemble du projet en changeant la classe FoodBankDB.

Et voici ma couche de logique métier:

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

Et enfin et surtout, ma couche de présentation:

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

Cela fonctionnait bien si je ne divisais pas la couche d'accès aux données et la classe de chaîne de connexion. Quelqu'un sait-il comment résoudre cette erreur?

Merci d'avance.

portion mise à jour

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

Cela ne fonctionne pas car vous fermez la connexion avant de retourner le lecteur. Reader ne fonctionne que lorsque la connexion est ouverte:

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

return result; // here the reader is not valid

D'une manière générale, vous ne devez pas renvoyer un lecteur vers une couche métier. Le lecteur ne doit être utilisé que dans la couche d'accès aux données. Il doit être utilisé, puis il et la connexion doivent être fermées.

Vous devriez plutôt renvoyer un objet qui peut fonctionner après la fermeture de la connexion, par exemple un DataSet ou DataTable ou encore une collection de DTO. Par exemple:

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

Le précédent est un bon exemple ... Mais vous pouvez également le faire en utilisant le code ci-dessous qui est automatically fermez une instance de connection lorsque la méthode datareader.close() est appelée ...

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