Recently, while working on one of my organization’s project. We wrote a generic extension method on the data reader class that returns the IEnumerable of the generic type.So, essentially what this does is returns an IEnumberable of the objects after reading various values from the datareader.(Dont ask me why are we doing this, why aren’t we using any ORM. We still want to use legacy data layer(organization’s decision). Since, this blog is not about why this decision was made, I will try to focus on the issue, that we faced while writing this for the first time. Am, planning to post this on stackoverflow.com as well to receive feedback to understand better way to resolve this.So, Initial code was

public static IEnumerable MapTo(this IDataReader reader) where T : new() { return reader.MapTo(null); } public static IEnumerable MapTo(this IDataReader reader, Action<IDataReader, T> customMappingFunction) where T : new() { using (reader) while (!reader.IsClosed && reader.Read()) { var nextItem = new T(); nextItem.InjectFrom(reader); if (customMappingFunction != null) customMappingFunction(reader, nextItem); yield return nextItem; } }

As you can see one method is just an overload of the real method. Issue with this method is that if try doing something like following,

// In case of lazy loading call to first count would return the correct value and the second call would return 0 var listOfEmployee = datareader.MapTo(); Console.WriteLine(listOfEmployee.Count()); Console.WriteLine(listOfEmployee.Count());

It will not work since next call is not resetting datareader, even though this would not work, chainabilty (fluent Interface) on first call will still work, Since this is how yield return works.

This is inherent problem of the data reader, Since you cann’t reset a data reader. So, because of that you can’t use lazy loading with data readers. and if you enable lazy loading then you have to call ToList() after call to MapTo(). otherwise you can lose the IEnumerable.

Code of DataReader Injection Class (This class is based on OMU Value Injector)

public class DataReaderInjection : KnownSourceValueInjection { protected override void Inject(IDataReader source, object target, PropertyDescriptorCollection targetProps) { for (var i = 0; i < source.FieldCount; i++) { var activeTarget = targetProps.GetByName(source.GetName(i), true); if (activeTarget == null) continue; var value = source.GetValue(i); if (value == DBNull.Value) continue; activeTarget.SetValue(target, value); } } }