I'm using a third party library which returns a data reader. I would like a simple way and as generic as possible to convert it into a List of objects.
For example, say I have a class 'Employee' with 2 properties EmployeeId and Name, I would like the data reader (which contains a list of employees) to be converted into List< Employee>.
I guess I have no choice but to iterate though the rows of the data reader and for each of them convert them into an Employee object that I will add to the List. Any better solution? I'm using C# 3.5 and ideally I would like it to be as generic as possible so that it works with any classes (the field names in the DataReader match the property names of the various objects).
A SqlDataAdapter is typically used to fill a DataSet or DataTable and so you will have access to the data after your connection has been closed (disconnected access). The SqlDataReader is a fast forward-only and connected cursor which tends to be generally quicker than filling a DataSet/DataTable.
DataReader provides faster performance, but has read-only and forward-only access. DataSet, on the other hand, is high resource-consuming, but offers more control and a disconnected nature.
The SqlDataReader is used to read a row of record at a time which is got using SqlCommand. It is read only, which means we can only read the record; it can not be edited. And also it is forward only, which means you can not go back to a previous row (record).
Do you really need a list, or would IEnumerable be good enough?
I know you want it to be generic, but a much more common pattern is to have a static Factory method on the target object type that accepts a datarow (or IDataRecord). That would look something like this:
public class Employee { public int Id { get; set; } public string Name { get; set; } public static Employee Create(IDataRecord record) { return new Employee { Id = record["id"], Name = record["name"] }; } }
.
public IEnumerable<Employee> GetEmployees() { using (var reader = YourLibraryFunction()) { while (reader.Read()) { yield return Employee.Create(reader); } } }
Then if you really need a list rather than an IEnumerable you can call .ToList()
on the results. I suppose you could also use generics + a delegate to make the code for this pattern more re-usable as well.
Update: I saw this again today and felt like writing the generic code:
public IEnumerable<T> GetData<T>(IDataReader reader, Func<IDataRecord, T> BuildObject) { try { while (reader.Read()) { yield return BuildObject(reader); } } finally { reader.Dispose(); } } //call it like this: var result = GetData(YourLibraryFunction(), Employee.Create);
You could build an extension method like:
public static List<T> ReadList<T>(this IDataReader reader, Func<IDataRecord, T> generator) { var list = new List<T>(); while (reader.Read()) list.Add(generator(reader)); return list; }
and use it like:
var employeeList = reader.ReadList(x => new Employee { Name = x.GetString(0), Age = x.GetInt32(1) });
Joel's suggestion is a good one. You can choose to return IEnumerable<T>
. It's easy to transform the above code:
public static IEnumerable<T> GetEnumerator<T>(this IDataReader reader, Func<IDataRecord, T> generator) { while (reader.Read()) yield return generator(reader); }
If you want to automatically map the columns to properties, the code idea is the same. You can just replace the generator
function in the above code with a function that interrogates typeof(T)
and sets the properties on the object using reflection by reading the matched column. However, I personally prefer defining a factory method (like the one mentioned in Joel's answer) and passing a delegate of it into this function:
var list = dataReader.GetEnumerator(Employee.Create).ToList();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With