following is the extension method to convert a datareader to the an object using OMU value injector based “DataReaderInjection” class.
public static IEnumerable<T> MapTo<T>(this IDataReader reader) where T : new() {
return reader.MapTo<T>(null);
}
public static IEnumerable<T> MapTo<T>(this IDataReader reader, Action<IDataReader, T> customMappingFunction) where T : new() {
using (reader)
while (!reader.IsClosed && reader.Read()) {
var nextItem = new T();
nextItem.InjectFrom<DataReaderInjection>(reader);
if (customMappingFunction != null)
customMappingFunction(reader, nextItem);
yield return nextItem;
}
}
this method has a bug since once you call this method and datareader is closed, next call would return an empty IEnumerable,To fix this I changed above code to following.
public static class DataAccessExtensions
{
public static IEnumerable<T> MapTo<T>(this IDataReader reader) where T : new() {
return reader.MapTo<T>(null);
}
private static Dictionary<int, IEnumerable> dataReaderCache = new Dictionary<int, IEnumerable>();
private static object lockObj = new object();
public static IEnumerable<T> MapTo<T>(this IDataReader reader, Action<IDataReader, T> customMappingFunction) where T : new() {
lock (lockObj)
{
if (dataReaderCache.ContainsKey(reader.GetHashCode()))
return dataReaderCache[reader.GetHashCode()] as IEnumerable<T>;
}
List<T> finalList = new List<T>();
using (reader) {
while (!reader.IsClosed && reader.Read()) {
var nextItem = new T();
nextItem
.InjectFrom<DataReaderInjection>(reader);
if (customMappingFunction != null)
customMappingFunction(reader, nextItem);
finalList.Add(nextItem);
}
}
lock (lockObj)
{
dataReaderCache.Add(reader.GetHashCode(), finalList);
}
return finalList;
}
}
What do you guys think will this work
It’s not a bug, datareaders are forward-only iterators, you only get to iterate them once. If you need to iterate over the results more than once, cache the IEnumerable you return. The simplest way to do this is to wrap it in a
List<T>, or you can cache it lazily using Rx’s MemoizeAll()