开发者

generic method to get linq result to datatable for select new with multiple selects

I'm trying to get the result of a join query with multiple selects into a dataTable, without selecting every fields separately.

This is the setup:

public class info
{
    public int id {get;set;}
    public int linked { get; set; }
    public int someNumber { get; set; }
}

        List<info> myInfoList = new List<info>();
        myInfoList.Add(new info { id = 20110102, linked = 1, someNumber = 1 });
        myInfoList.Add(new info { id = 20110103, linked = 2, someNumber = 3 });
        myInfoList.Add(new info { id = 20110104, linked = 3, someNumber = 4 });
        myInfoList.Add(new info { id = 20110105, linked = 4, someNumber = 5 });
        myInfoList.Add(new info { id = 20110106, linked = 5, someNumber = 6 });
        myInfoList.Add(new info { id = 20110107, linked = 1, someNumber = 1 });
        myInfoList.Add(new info { id = 20110108, linked = 2, someNumber = 2 });
        myInfoList.Add(new info { id = 20110109, linked = 3, someNumber = 3 });
        myInfoList.Add(new info { id = 20110110, linked = 4, someNumber = 1 });
        myInfoList.Add(new info { id = 20110111, linked = 1, someNumber = 1 });
        myInfoList.Add(new info { id = 20110112, linked = 1, someNumber = 1 });
        myInfoList.Add(new info { id = 20110113, linked = 2, someNumber = 1 });
        myInfoList.Add(new info { id = 20110114, linked = 2, someNumber = 1 });
        myInfoList.Add(new info { id = 20110115, linked = 3, someNumber = 1 });

        List<info> myInfoList2 = new List<info>();
        myInfoList2.Add(new info { id = 20110102, linked = 1, someNumber = 1 });
        myInfoList2.Add(new info { id = 20110102, linked = 2, someNumber = 3 });
        myInfoList2.Add(new info { id = 20110102, linked = 3, someNumber = 4 });

        List<info> myInfoList3 = new List<info>();
        myInfoList3.Add(new info { id = 20110102, linked = 1, someNumber = 1 });
        myInfoList3.Add(new info { id = 20110103, linked = 2, someNumber = 3 });
        myInfoList3.Add(new info { id = 20110112, linked = 3, someNumber = 4 });


        var outerJoinTest = from x in myInfoList
                            join y in myInfoList2
                            on x.linked equals y.linked
                            into temp
                            from t in temp.DefaultIfEmpty()
                            join z in myInfoList3
                            on x.id equals z.id
                            into temp2
                            from t2 in temp2.DefaultIfEmpty()
                            select new { x, t, t2 };

I normally use this method to convert linq queries to datatable:

        private DataTable LINQToDataTable<T>(IEnumerable<T> varlist)
    {

        DataTable dtReturn = new DataTable();

        PropertyInfo[] columnNames = null;

        if (varlist == null) return dtReturn;

        foreach (T rec in varlist)
        {
            if (columnNames == null)
            {
                columnNames = ((Type)rec.GetType()).GetProperties();
                foreach (PropertyInfo pi in columnNames)
                {
                    Type colType = pi.PropertyType;

                    if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                    {
                        colType = colType.GetGenericArguments()[0];
                    }

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

            DataRow dr = dtReturn.NewRow();

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

            dtReturn.Rows.Add(dr);
        }

        return dtReturn;
    }

But this method doesn't work properly with multiple anonymous selects.

I get this result:

generic method to get linq result to datatable for select new with multiple selects

When i set a break point in the private DataTable LINQToDataTable(IEnumerable varlist) and hover above rec I can see the values I want to see in the datatable.

generic method to get linq result to datatable for select new with multiple selects

can someone help me out to change the method in a 开发者_Go百科way that it outputs the result like this:

generic method to get linq result to datatable for select new with multiple selects


How about something like this:

private class NestedPropertyInfo
{
    public PropertyInfo Parent { get; set; }
    public PropertyInfo Child { get; set; }
    public string Name { get { return Parent.Name + "_" + Child.Name; } }
}

private DataTable LINQToDataTable<T>(IEnumerable<T> varlist)
{
    DataTable dtReturn = new DataTable();
    NestedPropertyInfo[] columns = null;

    if (varlist == null) return dtReturn;

    foreach (T rec in varlist)
    {
        if (columns == null)
        {
            columns = (
                from p1 in rec.GetType().GetProperties()
                from p2 in p1.PropertyType.GetProperties()
                select new NestedPropertyInfo { Parent = p1, Child = p2 }
                ).ToArray();

            foreach (var column in columns)
            {
                var colType = column.Child.PropertyType;

                if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                {
                    colType = colType.GetGenericArguments()[0];
                }

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

        DataRow dr = dtReturn.NewRow();

        foreach (var column in columns)
        {
            var parentValue = column.Parent.GetValue(rec, null);
            var childValue = parentValue == null ? null : column.Child.GetValue(parentValue, null);
            dr[column.Name] = childValue ?? DBNull.Value;
        }

        dtReturn.Rows.Add(dr);
    }

    return dtReturn;
}

Also, not related to the question but you should really use collection initializers:

var myInfoList = new List<info>
{
    new info { id = 20110102, linked = 1, someNumber = 1 },
    new info { id = 20110103, linked = 2, someNumber = 3 },
    new info { id = 20110104, linked = 3, someNumber = 4 },
    // ...
};
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜