0

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?

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
DougJones
  • 774
  • 1
  • 9
  • 26

2 Answers2

0

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 =)

BeemerGuy
  • 8,139
  • 2
  • 35
  • 46
  • I would absolutely be ok with a reflection solution. The concern there obviously being performance, and it would depend on how much was needed. If it was needed on every column of every row I would suspect that would be a problem. If just once, no problem. I believe we'd be hitting a max of around 500 rows. – DougJones Nov 09 '10 at 00:23
  • Can you give me a sample instance of 'rows'? Is it just a bunch of similar objects? – BeemerGuy Nov 09 '10 at 00:31
  • It's a datatable. <% DataTable dt = GetData(); var rows = dt.AsEnumerable(); %> – DougJones Nov 09 '10 at 00:46
  • OK I give up..... it's not possible given that it's not really clear how it would be accessible even if we made those groupings. I'm sure there's an easier way to go around all that. Sorry =/ – BeemerGuy Nov 09 '10 at 01:27
0

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.

Community
  • 1
  • 1
DougJones
  • 774
  • 1
  • 9
  • 26