2013-12-09 2 views
10

У меня есть Неверная попытка вызова Чтение, когда ошибка чтения закрыта, когда я выполняю проект на 3 уровня на языке C#. То, что я пытаюсь сделать, это получить столбцы данных адреса путем объединения двух таблиц вместе и отображения в выпадающем списке. Вот мой уровень доступа к данным:C# Неверная попытка вызова Чтение, когда читатель закрыт

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.

И это мой бизнес-логики:

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

ответ

20

Это не работает, потому что вы закрыть соединение перед возвращением читателя. Читатель работает только при открытии соединения:

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

return result; // here the reader is not valid 

Вообще говоря, вы не должны возвращать читателя на бизнес-уровень. Считыватель должен использоваться только на уровне доступа к данным. Он должен использоваться, а затем он и соединение должны быть закрыты.

Вы должны скорее вернуть объект, который может работать после закрытия соединения, например. a 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; 
} 
+1

бы вы ум, чтобы показать мне пример о том, как это решить? Потому что я немного смущен –

+1

См. Пример выше. Я надеюсь, что нет никаких небольших ошибок, поскольку я не могу запустить код сейчас. – Szymon

+0

Я должен закодировать GetConnectionString() как обновленную часть? Или я делаю не так? –

3

Предыдущий один хороший пример ... Но вы также можете выполнить его ниже код, который automatically закрыть connection случай, когда datareader.close() метод называется ...

reader = Sqlcmd.ExecuteReader(CommandBehavior.CloseConnection);