Using dynamic LINQ for GroupBy on DataTable
I have seen quite a few ways to get dynamic LINQ to work for the .GroupBy
, but every one that I see seems to expect a hard coded entity. I want to reproduce the following as dynamic LINQ:
//need dynamic LINQ for this
var groupedRows = rows.GroupBy(z => new { make = z["make"], model = z["model"] })
.Select开发者_运维百科(x => x.Key);
I'd like to be able to just do this, making the entire function a string:
var groupedRows = rows.GroupBy(z => "new { make = z[\"make\"], model = z[\"model\"] }")
I realize that if it were only a regular entity, I could do this
mylist.GroupBy(z => new { make = z.make, model = z.model }).Select(x => x.Key);
If I had that regular entity, I could use Mitsu's dynamic GroupByMany.
I am trying to get this to work with a regular datatable (not strongly typed). Any ideas?
I don't think that's possible; this suggests you want the C# compiler to compile your string at runtime =)
The problem isn't the "make" and "model" indexers, it's the members in the new instances you're returning; those can only be textually represented by Reflection, but I know LINQ-to-Entities doesn't support its functions, not sure if normal LINQ will.
Would you be ok with a Reflection solution?
I wanna know if you're ok with it before I spend two hours trying to make it work =)
Ok, I was able to get this working with both reflection and compiling code at runtime using the Mono Compiler as a Service (MCS). Utilizing the question Injecting a variable into the Mono.CSharp.Evaluator (runtime compiling a LINQ query from string), I came up with the following solution (#2 in the answer to that question):
DataTable dt = GetData();
var dataRows = dt.AsEnumerable();
//Initializing the evaluator
Evaluator.Init(new string[0]);
Evaluator.ReferenceAssembly(Assembly.GetAssembly(typeof(DataRow)));
Evaluator.ReferenceAssembly(Assembly.GetExecutingAssembly());
Evaluator.Run(@"using System;
using System.Linq;
using System.Collections.Generic;
using System.Data;
using MyNamespace;");
var func = (Func<DataRow, object>)Evaluator.Evaluate(@"new Func<DataRow,object>(z => new
{
make = z[""make""],
model = z[""model""]
});");
dataRows.GroupBy(func).Select(x => x.Key);
So that compiles the function at runtime, then calls the function in the GroupBy for each row. When I needed the value of make or model, I then needed to use reflection to get to that value through my GetPropertyValue extension method.
I still can't get LINQ working within the MCS, even after following the Mono Compiler as a Service (MCS) question, but just using it to creating the function did what I needed it to do.
精彩评论