Joe*_*orn 10 .net c# database .net-2.0
我们有很多数据层代码遵循这个非常通用的模式:
public DataTable GetSomeData(string filter)
{
string sql = "SELECT * FROM [SomeTable] WHERE SomeColumn= @Filter";
DataTable result = new DataTable();
using (SqlConnection cn = new SqlConnection(GetConnectionString()))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("@Filter", SqlDbType.NVarChar, 255).Value = filter;
result.Load(cmd.ExecuteReader());
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
我想我们可以做得更好一点.我现在的主要抱怨是它强制将所有记录加载到内存中,即使对于大型集合也是如此.我希望能够利用DataReader的能力,一次只能在ram中保留一条记录,但如果我直接返回DataReader,则在离开using块时会切断连接.
如何改进这一点以允许一次返回一行?
Joe*_*orn 13
再次,为问题撰写我的想法的行为揭示了答案.具体来说,我写的"一次一行"的最后一句话.我意识到我并不在乎它是一个datareader,只要我可以逐行枚举它.这导致我这样:
public IEnumerable<IDataRecord> GetSomeData(string filter)
{
string sql = "SELECT * FROM [SomeTable] WHERE SomeColumn= @Filter";
using (SqlConnection cn = new SqlConnection(GetConnectionString()))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("@Filter", SqlDbType.NVarChar, 255).Value = filter;
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
一旦我们移动到3.5并且可以开始在结果上使用其他linq运算符,这将更好地工作,我喜欢它,因为它让我们开始考虑每个层之间的"管道",以便返回大量的查询结果.
缺点是对于持有多个结果集的读者来说会很尴尬,但这种情况非常罕见.
更新
自2009年我第一次开始使用此模式以来,我了解到最好是将其设置为泛型IEnumerable<T>
返回类型并添加Func<IDataRecord, T>
参数以将DataReader状态转换为循环中的业务对象.否则,延迟迭代可能会出现问题,因此您每次都会在查询中看到最后一个对象.
你想要的是一个支持的模式,你必须使用
cmd.ExecuteReader(CommandBehavior.CloseConnection);
Run Code Online (Sandbox Code Playgroud)
并从using()
GetSomeData()方法中删除它们.呼叫者必须提供例外安全保障,以确保读者能够关闭.