ArtK
ArtK

Reputation: 1185

Dynamically select columns in LINQ statement

Similar question exists but solution does not apply. I'm finishing a small program that allows user to import 2 data tables and join to get results. Here's relevant code:

List<DataRow> list1 = ds1.Tables[0].AsEnumerable().ToList<DataRow>();
            List<DataRow> list2 = ds2.Tables[0].AsEnumerable().ToList<DataRow>();
            var v = (from t1 in list1
                     join t2 in list2
                     on t1.Field<string>(ds1ColInx) equals t2.Field<string>(ds2ColInx)
                     select new
                     {
                         t1,
                         t2
                     }).ToList();

But this can't be fed into DataGridView, quite obviously. Now, I also have a string array of column names and column indexes for each table and column that user wants to see. How can I plug that into select statement?

Upvotes: 1

Views: 4670

Answers (2)

NetMage
NetMage

Reputation: 26917

I would suggest converting v to a DataTable and copying the columns desired. Using cols as your desired columns:

string[] cols;
var dt = new DataTable();
var t1cols = ds1.Tables[0].Columns.Cast<DataColumn>().Select(dc => dc.ColumnName).ToHashSet();
var tcols = t1cols.Cast<DataColumn>().Union(ds2.Tables[0].Columns.Cast<DataColumn>()).ToDictionary(dc => dc.ColumnName);

foreach (var cname in cols)
    dt.Columns.Add(new DataColumn(cname, tcols[cname].DataType));

foreach (var vr in v) {
    var nr = dt.NewRow();
    foreach (var cname in cols)
        nr[cname] = t1cols.Contains(cname) ? vr.t1[cname] : vr.t2[cname];
    dt.Rows.Add(nr);
}

Now you can just assign dt to GridView.DataSource.

Note that bad things will happen if t1 and t2 have any columns with the same name, in which case you should rename them all with a table prefix in t1cols, tcols and when adding them to dt.Columns.

Upvotes: 1

Josh Darnell
Josh Darnell

Reputation: 11433

You can bring in the Microsoft-developed "System.Linq.Dynamic" library to accomplish your goal. You can find it on NuGet here:

http://www.nuget.org/packages/System.Linq.Dynamic/

And the source is here:

https://github.com/kahanu/System.Linq.Dynamic

Then reference System.Linq.Dynamic, and you will have access to new extension methods that accept strings rather than expressions.

I have only every used it with the lambda-based LINQ extension methods, which enable you to do things like this:

.Select("column1, column2, column3").ToList();

I have attempted to rewrite your query using the lambda syntax below, although it is untested:

var v = list1.Join(
            list2,
            t1 => t1.Field<string>(ds1ColInx),
            t2 => t2.Field<string>(ds2ColInx),
            (t1, t2) => new {t1, t2});

v.Select(columnList).ToList();

Note: in this situation, you may need to play around a bit with your column strings (for instance, I think you'll need to prefix them with "t1" or "t2" depending on which table they are actually in).

Upvotes: 1

Related Questions