我们有很多数据层代码都遵循这个非常通用的模式:
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;
}
我想我们可以做得更好一点。我现在主要的抱怨是它强制将所有记录加载到内存中,即使对于大型记录也是如此。我希望能够利用 DataReader 一次只在 RAM 中保留一条记录的能力,但如果我直接返回 DataReader,则在离开 using 块时连接将被切断。
我该如何改进它以允许一次返回一行?
再一次,我对这个问题的思考的行为揭示了答案。具体来说,最后一句我写的是“一次一行”。我意识到我并不真正关心它是一个数据读取器,只要我可以逐行枚举它即可。这让我想到了这一点:
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;
}
}
}
}
一旦我们迁移到 3.5,并且可以开始在结果上使用其他 linq 运算符,这将工作得更好,我喜欢它,因为它让我们开始思考每层之间的“管道”,用于返回大量的查询结果。
缺点是读者持有多个结果集会很尴尬,但这种情况极为罕见。
Update
自从 2009 年我第一次开始使用这个模式以来,我了解到最好也将其设为通用模式IEnumerable<T>
返回类型并添加Func<IDataRecord, T>
参数将 DataReader 状态转换为循环中的业务对象。否则,惰性迭代可能会出现问题,例如您每次都会看到查询中的最后一个对象。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)