patterncsharpMinor
Converting recordsets to POCO
Viewed 0 times
convertingpocorecordsets
Problem
The goal this method was to emulate the way EF or Dapper return to you concrete POCO classes instead of recordsets when querying your db. Our current code is riddled with iterations over recordsets and I want to consolidate to an extension method that can convert the recordset into an
Review
I'm concerned about how efficient this will be. When querying the db for a single or handful of records I'm not concerned but we sometimes query for an entire table (i.e. ~100,000 records) and in that case will the iterations in this start to cause performance issues? Is there a better way to resolve the recordsets to classes without iterating? Any other constructive remarks appreciated.
used as...
Post Review Update
After great feedback from Heslacher and t3chb0t the following code has been finalized. Note there was a change in the requirements and sister method was created
```
public static IList AsList(this Recordset rs) where T : class, new()
{
var results = new List();
if (rs == null) throw new ArgumentNullException("rs");
if (rs.Eof) return results;
IList properties = GetProperties();
while (!rs.Eof)
{
results.Add(CreateInstance(propertie
Enumerable.Review
I'm concerned about how efficient this will be. When querying the db for a single or handful of records I'm not concerned but we sometimes query for an entire table (i.e. ~100,000 records) and in that case will the iterations in this start to cause performance issues? Is there a better way to resolve the recordsets to classes without iterating? Any other constructive remarks appreciated.
public static IEnumerable AsList(this Recordset rs) where T : new()
{
IEnumerable props = new List(typeof(T).GetProperties()).Where(p => p.CanWrite);
List results = new List();
while (!rs.Eof)
{
T obj = new T();
foreach (PropertyInfo property in props)
{
var val = rs[property.Name].Value;
if (val != null) property.SetValue(obj, Convert.ChangeType(val, property.PropertyType));
}
rs.MoveNext();
results.Add(obj);
}
return results.AsEnumerable();
}used as...
Recordset rs = new Recordset();
rs.Open("select * from Users", connection)
IEnumerable results = rs.AsList();Post Review Update
After great feedback from Heslacher and t3chb0t the following code has been finalized. Note there was a change in the requirements and sister method was created
As() to create a single class instance from a recordset. The feedback from the review has been applied to it as well.```
public static IList AsList(this Recordset rs) where T : class, new()
{
var results = new List();
if (rs == null) throw new ArgumentNullException("rs");
if (rs.Eof) return results;
IList properties = GetProperties();
while (!rs.Eof)
{
results.Add(CreateInstance(propertie
Solution
public static IEnumerable AsList(this Recordset rs) where T : new()
{
..
List results = new List();
..
return results.AsEnumerable();
}This might be very inefficient because when I see that a method returns an
IEnumerable I assume its execution is deferred so I automatically do AsList(..).ToList() to execute it but what it actually does, is to iterate the list twice. First time to create the first list and then to create the second list. You should either create a real deferred method or return the List so there is no doubt about the result.IEnumerable props = new List(typeof(T).GetProperties()).Where(p => p.CanWrite);You are executing this
Where query for each record because the list wrapps only the GetProperties part (which is an array anyway so I don't understand why you convert it into a list in the first place - linq can work with arrays). You need to call the ToList extension after the Wherevar properties = typeof(T).GetProperties().Where(p => p.CanWrite).ToList();I also suggest moving the object creation into a separate method so that you don't have any nested loops like this:
public static IEnumerable AsList(this Recordset rs) where T : new()
{
var properties = typeof(T).GetProperties().Where(p => p.CanWrite).ToList();
while (!rs.Eof)
{
yield return CreateInstance(properties, rs);
rs.MoveNext();
}
}
private static T CreateInstance(IEnumerable properties, Row row) where T : new()
{
var obj = new T();
foreach (var property in properties)
{
var value = row[property.Name].Value;
if (value != null) property.SetValue(obj, Convert.ChangeType(value, property.PropertyType));
}
return obj;
}Code Snippets
public static IEnumerable<T> AsList<T>(this Recordset rs) where T : new()
{
..
List<T> results = new List<T>();
..
return results.AsEnumerable();
}IEnumerable<PropertyInfo> props = new List<PropertyInfo>(typeof(T).GetProperties()).Where(p => p.CanWrite);var properties = typeof(T).GetProperties().Where(p => p.CanWrite).ToList();public static IEnumerable<T> AsList<T>(this Recordset rs) where T : new()
{
var properties = typeof(T).GetProperties().Where(p => p.CanWrite).ToList();
while (!rs.Eof)
{
yield return CreateInstance<T>(properties, rs);
rs.MoveNext();
}
}
private static T CreateInstance<T>(IEnumerable<PropertyInfo> properties, Row row) where T : new()
{
var obj = new T();
foreach (var property in properties)
{
var value = row[property.Name].Value;
if (value != null) property.SetValue(obj, Convert.ChangeType(value, property.PropertyType));
}
return obj;
}Context
StackExchange Code Review Q#159267, answer score: 3
Revisions (0)
No revisions yet.