LINQ to DataTable

We have been adopting Linq slowly but surely and have run into some issues we never had to deal with in the past.  Currently I use DataSets in VS2005 for everything.  These are nice since they return DataTables easily and allow updates / inserts / etc without issue. 

When we dove into Linq and had to return a DataTable for the first time we were stuck.  Looking through examples & searching online did not return much. I did find an example by Kevin Goff in CoDe Magazine which outlined 13 tips for Linq.  This worked great except I had some issues with null datatypes. Those issues should be fixed in the sample below.

The following code outlines a quick way using Linq to query a database and return the results to a DataTable.

Here is my newly created class:

static public class ConvertDataTable

{

public static DataTable ToADOTable<T>(this IEnumerable<T> varlist, CreateRowDelegate<T> fn)

{

DataTable dtReturn = new DataTable();

// Could add a check to verify that there is an element 0

T TopRec = varlist.ElementAt(0);

// Use reflection to get property names, to create table

// column names

PropertyInfo[] oProps =

((Type)TopRec.GetType()).GetProperties();

foreach (PropertyInfo pi in oProps)

{

Type colType = pi.PropertyType;if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))

{

colType = colType.GetGenericArguments()[0];

}

dtReturn.Columns.Add(
new DataColumn(pi.Name, colType));

}

foreach (T rec in varlist)

{

DataRow dr = dtReturn.NewRow();foreach (PropertyInfo pi in oProps)
{
   dr[pi.Name] = pi.GetValue(rec,
null) == null ? DBNull.Value : pi.GetValue(rec, null);
}

dtReturn.Rows.Add(dr);

}

return (dtReturn);

}

public delegate object[] CreateRowDelegate<T>(T t);

}

Here is the usage in code:

LData.MyDataContext db = new LData.MyDataContext();
var query = from p in db.Extensions
w
here p.DepartmentNumber == "412"select p;

DataTable dt = query.ToADOTable(rec => new object[] { query });

 

Hope this helps someone else out.

~ Steve

 

25 Comments

  • Thanks Steve.
    I was looking for something clean that does just this.

  • Can you give a brief sample of how this is called?

  • Mark,

    There's an example listed above on how to use it:

    1. Create your data context
    LData.MyDataContext db = new LData.MyDataContext();

    2. Generate your query
    var query = from p in db.Extensions
    where p.DepartmentNumber == "412"select p;

    3. Convert the result to a datatable
    DataTable dt = query.ToADOTable(rec => new object[] { query });

    Let me know if that works for you or not.

    ~ Steve

  • What if my datacontext is a datatable instead of a database? I have to append the asEnumerable() method to the datatable in the linq statement so that it doesn't throw an error on build.

    The results contain rowerrors and fail.

  • Module ConvertDataTable

    _
    Public Function ToDataTable(Of T)(ByVal value As IEnumerable(Of T)) As DataTable

    Dim returnTable As New DataTable
    Dim firstRecord = value.First

    For Each pi In firstRecord.GetType.GetProperties
    returnTable.Columns.Add(pi.Name, pi.GetValue(firstRecord, Nothing).GetType)
    Next

    For Each result In value
    Dim nr = returnTable.NewRow
    For Each pi In result.GetType.GetProperties
    nr(pi.Name) = pi.GetValue(result, Nothing)
    Next
    returnTable.Rows.Add(nr)
    Next

    Return returnTable

    End Function

    End Module

  • I am getting a CTE of...

    Error 1 The non-generic type 'System.Collections.IEnumerable' cannot be used with type arguments C:\Code\Team\Clear\Web\App_Code\Business\Components\ConvertDataTable.cs 20 45 C:\...\Web\

    ...when I try to compile...

    ...my using statements are...

    using System;
    using System.Data;
    using System.Collections;
    using System.Configuration;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml;
    using System.Xml.Linq;

    ...and the class is exactly as you pasted it above.

    Ideas?

    Thank you.

    -- Mark Kamoski

  • These using statements work...


    using System;
    using System.Data;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Configuration;
    using System.Linq;
    using System.Reflection;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Linq;

  • awesome man. saved me a ton of work!

  • You Rock! Code works great, and saved me a lot of heart ache!

  • This is just fantastic. For ASP.NET stuff when you want to bind to tabular information it is just perfect.
    Thanks!

  • It's help me resolved my problem.

    thanks

  • What about the properties order?
    GetProperties() doesn´t return the properties in a native or alphabetical order.......
    So... The column order will not be *always* the same for the exactly same query.....

  • Thanks that was almost too easy.

  • Thanks Very Much,

    Still need to play with it, but on first galnce it has solved my problem. Grateful for people sharing code like this, it saves days of hassle.

  • Thanks for this code!!

  • Thanks steve
    This code help to resolveds

  • Hey, thanks for this code. The bad thing is that I'm getting an error that I just cannot solve.

    CS0121: The call is ambiguous between the following methods or properties: 'CustomerPriceAgreement.ConvertDataTable.ToADOTable(System.Collections.Generic.IEnumerable, CustomerPriceAgreement.ConvertDataTable.CreateRowDelegate)' and 'CustomerPriceAgreement.ConvertDataTable.ToADOTable(System.Collections.Generic.IEnumerable, CustomerPriceAgreement.ConvertDataTable.CreateRowDelegate)'


    Any ideas?

  • HEy Thankfor the code , I got an error as below

    f:\CMS\CMS\CMS\App_Code\clsUser.cs(280,22): error CS0121: The call is ambiguous between the following methods or properties: 'CMS.clsConvertDataTable.ToADOTable(System.Collections.Generic.IEnumerable, CMS.clsConvertDataTable.CreateRowDelegate)' and 'CMS.clsConvertDataTable.ToADOTable(System.Collections.Generic.IEnumerable, CMS.clsConvertDataTable.CreateRowDelegate)'
    f:\CMS\CMS\CMS\App_Code\clsUser.cs(322,26): error CS0121: The call is ambiguous between the following methods or properties: 'CMS.clsConvertDataTable.ToADOTable(System.Collections.Generic.IEnumerable, CMS.clsConvertDataTable.CreateRowDelegate)' and 'CMS.clsConvertDataTable.ToADOTable(System.Collections.Generic.IEnumerable, CMS.clsConvertDataTable.CreateRowDelegate)'

  • Just wanted to say thanyou very much. I was going a little insane until I found your article. Works like a dream.

  • Great Code Mate !!!!!

  • It seems that the fn parameter (and the associated delegate) are basically dead code...?

    Otherwise - thanks a ton! You helped me out a lot!

  • It seems simple enough to do this conversion without relying on there being any rows in the anonymous collection. Based on this on my previous comment, I respectfully submit the following method to amend the original:


    public static DataTable ToADOTable(this IEnumerable varlist)
    {
    DataTable dtReturn = new DataTable();
    // Use reflection to get property names, to create table
    // column names
    PropertyInfo[] oProps = typeof(T).GetProperties();
    foreach (PropertyInfo pi in oProps)
    {
    Type colType = pi.PropertyType; if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable)))
    {
    colType = colType.GetGenericArguments()[0];
    }
    dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
    }
    foreach (T rec in varlist)
    {
    DataRow dr = dtReturn.NewRow(); foreach (PropertyInfo pi in oProps)
    {
    dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue(rec, null);
    }
    dtReturn.Rows.Add(dr);
    }

    return (dtReturn);
    }

  • Great post. I just used the last post to create my DataTable and it worked straight out of the box. GREAT code! Although I was slightly confused by the generic bit in the first foreach statement.

  • ToADOTable is great solution :). this is my first post in fact feedback on the Internet and ToADOTable is reason behind this :).. Thank you

  • Thanks it helps me a lot

Comments have been disabled for this content.