Introducing DataReaderAdapter: Adds AsDataReader()/AsDataReaderOfObjects() to IEnumerable<T>

Yesterday, we released BenGribaudoLLC.IEnumerableHelpers.DataReaderAdapter as a NuGet package!

What does it to?

Adapts IEnumerable<T> to the IDataReader interface. Enables enumerable sequences to be used where a data reader is expected.

Great for loading data from a List<T>, LINQ expression or CSV parser into a database using SqlBulkCopy! Streams data to SqlBulkCopy, bypassing the need to first materialize the entire sequence in memory and load it into a DataTable.

var data = from p in DataContext.People
            where o.Age >= 18
            select new { p.FirstName, p.LastName, p.Age};

using (var bulkCopy = new SqlBulkCopy(connection)) {
  bulkCopy.DestinationTableName = "Adults";
  bulkCopy.WriteToServer(data.AsDataReader());
}

How does it work?

Each item in the enumerable becomes a record returned by the data reader.

AsDataReader()

Used when the enumerable contains IEnumerable<T>s. The items in the inner enumerable become the data record’s fields. Optionally, field names may be provided.

var data = new[] {
  new[] { "Joe", "Smith" },
  new[] { "Bob", "Brown" }
};
 
var reader = data.AsDataReader();
//var reader = data.AsDataReader(fieldNames: new[] { "FirstName", "LastName" });
while (reader.Read())
{
  Console.WriteLine($"{reader.GetValue(0) } {reader.GetValue(1)}");
  //Console.WriteLine($"{reader["FirstName"] } {reader["LastName"]}");
}
// Outputs:
// Joe Smith
// Bob Brown

AsDataReaderOfObjects()

Used when the enumerable contains objects whose public readable instance properties should become the fields returned by the data reader.

var data = new[]
{
  new Item { ItemNumber = 1, Name = "Widget", Price = 10.00m },
  new Item { ItemNumber = 2, Name = "Gadget", Price = 4.99m },
};
 
var reader = data.AsDataReaderOfObjects();
while (reader.Read())
{
  var priceForTwo = reader.GetDecimal(reader.GetOrdinal("Price")) * 2;
  Console.WriteLine($"Item # {reader["ItemNumber"]} - {priceForTwo:C2}");
}

// Outputs:
// Item 1 - $20.00
// Item 2 - $9.98

Notes

  • .Net Standard 1.6’s SqlBulkCopy.WriteToServer() does not work with IDataReader, limiting this package’s usefulness on that platform. .Net Standard 2.0 should resolve this issue as it will add a SqlBulkCopy.WriteToServer overload that accepts IDataReader.
  • This package’s data reader implementation does not support IDataReader.GetSchemaTable().

Leave a Reply

Your email address will not be published. Required fields are marked *