我在用C#语言执行3层项目时,尝试关闭阅读器时发生无效尝试调用Read的错误。我想做的是通过将两个表连接在一起来检索地址数据列,并显示在下拉列表中。这是我的数据访问层:
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; }
它不起作用,因为您在返回阅读器之前先关闭了连接。阅读器仅在连接打开时才起作用:
result = command.ExecuteReader(); connection.Close(); return result; // here the reader is not valid
一般来说,您不应该使读者回到业务层。阅读器应仅在数据访问层中使用。应该先使用它,然后再关闭连接。
您应该返回一个在连接关闭后可以工作的对象,例如一个DataSet或DataTable多个DTO的集合。例如:
DataSet
DataTable
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; }