问题
I have a method that returns a data reader. Normally I would wrap a using around the data reader so that it gets disposed nicely after I iterate through it. THe problem is that I've chosen to consume the data reader using Linq, which means that the defered execution causes the reader to get disposed early. Is there a proper pattern to consume and dispose of the data reader using Linq without having to built a complete collection of it's contents?
using (System.Data.SqlClient.SqlDataReader reader = CallStoredProcedure())
{
return reader.Cast<System.Data.Common.DbDataRecord>().Select(rec => new ObjectModel.CollectorSummaryItem()
{
CollectorID = (int)rec[0],
Name = rec.IsDBNull(1) ? null : rec.GetString(1),
Information = rec.IsDBNull(2) ? null : rec.GetString(2)
});
}
回答1:
You need to actually read from the reader inside the using block:
using (System.Data.SqlClient.SqlDataReader reader = CallStoredProcedure())
{
while (reader.Read())
{
yield return new ObjectModel.CollectorSummaryItem()
{
CollectorID = (int)reader[0],
Name = reader.IsDBNull(1) ? null : reader.GetString(1),
Information = reader.IsDBNull(2) ? null : reader.GetString(2)
};
}
}
This will evaluate to code with the same or consistent return type with what you had before, but doesn't close the reader until after you're done reading from it.
回答2:
Shooting from the hip here. This should help you decouple the reader logic as well.
public IEnumerable<MyObject> ExecuteNonQuery(...)
{
...
using(var reader = comm.ExecuteReader())
{
var results = new List<MyObject>();
return reader
.Cast<System.Data.Common.DbDataRecord>()
.Select(rec => GetFromReader(rec))
.ToList();
}
}
public MyObject GetFromReader(IDataRecord rdr)
{
return new MyObject { Prop1 = rdr["prop1"], Prop2 = rdr["prop2"] };
}
来源:https://stackoverflow.com/questions/16179996/how-to-best-clean-up-a-sqldatareader-when-using-linq