Friday, March 09, 2007

LINQ's Missing ToDataTable Method Saga

Several LINQ pilgrims, including Julie Lerman, the authors of three books about LINQ (two published and one in process), Mike Taulty and I, have been attempting to find the IEnumerable<T>.ToDataTable and DataTable.LoadSequence methods in the Orcas March 2007 CTP's LINQ implementation.

Here's the answer from ADO.NET program manager Erick Thompson, author of the LINQ to DataSet documentation series, in the LINQ Project General Forum:

We decided to remove the ToDataTable for any sequence, as there isn't a correct way to always load data from a sequence into a DataTable. For example, what do you do with a sequence of Type A where some instances are also Type B, where B inherits from A? Do you extend the DataTable schema to allow for the additional fields in B? Throw an error? Not load the additional data?

We are looking at bringing this functionality back at some point. What would be helpful is a better understanding of what you would like to use it for. What LINQ to XXX queries do you want to load into a DataTable, and why?

My immediate reaction was that there would be few, if any, System.Data namespace members were such "always" restrictions applied to them.

Fabrice Marguerie's reply makes the most sense to me:

I would expect the behavior to be basic. I think that most of the time when we work with DataSets, we do not use mixed data types. Often the data will come from LINQ to SQL or LINQ to XML queries that return only of type of data as specified in their select clause.

I would bring back the ToDataTable and LoadSequence operators back to life, even if they throw exceptions in unsupported cases. These cases would be the minority, I think. Of these cases should be documented. It probably require more thought, but having ToDataTable use only the members of the base type (the generic type T of the sequence) can be an acceptable limitation, I think.

One issue is that operating on a non-homogeneous type would appear to throw runtime not compile-time, exceptions. A major objective of LINQ is to substitute compile-time for runtime exceptions.

Update 4/4/2007: Julie Lerman points to Fabio Claudio Ferracchiati's May 2006 to March 2007 comparison list post of March 7, 2007, that lists the differences between the two CTPs' LINQ implementation. Fabio is the author of LINQ for Visual C# 2005 and LINQ for VB 2005 books mentioned the first paragraph of this post. Fabio also has posted updated code for the C# title. You can buy either title as a downloadable eBook from Apress.

4 comments:

  1. Aren't the scenarios listed by Mr. Thompson already well-modeled by the DataSet.Merge algorithm and associated MissingSchemaAction enum?

    Seems to me that putting this tool into developers hands would be a great way to keep the simple case simple, and subject us to the same level of run-time error protection we currently enjoy - specifically typed exceptions. If I'm using a simpler domain logic pattern, involving DataSet, this is just what I need. If I am using a more sophisticated domain logic pattern, like Domain Model, I won't use the ToDataTable method, just as I don't use the DataSet. As typing is more important in this higher level of complexity, I'll use, and be thankful for, compile-time verification of LINQ expressions and types, leaving ToDataTable out of the equation.

    ReplyDelete
  2. Rory, you forget that a common use case is interacting with legacy code or tools that expect DataSet to work.
    Reporting tools often use DataSets as input for example. Another benefit of DataSets is that they can easily be persisted in XML or binary formats, a service that is not provided by LINQ.
    This means that converting the results of a LINQ to XXX query into a DataSet can be useful.

    ReplyDelete
  3. 've written a small library myself to accomplish this task. It uses reflection only for the first time an object type is to be translated to a datatable. It emits a method that will do all the work translating an object type.

    Its blazing fast. You can find it here: ModelShredder on GoogleCode

    ReplyDelete