2015-11-04 1 views
0

Je voudrais changer le code suivant pour gérer le regroupement de plus de 1 biensLinq: Groupe par plusieurs colonnes en utilisant la syntaxe Expression arbre

private Expression<Func<ProfileResultView, string>> DynamicGroupBy(string propertyName) 
{ 
    var parameterExp = Expression.Parameter(typeof(ProfileResultView), "x"); 
    var memberExp = Expression.PropertyOrField(parameterExp, propertyName); 
    return Expression.Lambda<Func<ProfileResultView, string>>(memberExp, parameterExp); 
} 

donc alors ce serait traduit à

GroupBy(x => new { x.Column1, x.Column2 }) 

comment puis-je écrire le type anonyme dans la syntaxe expression-arbre?

+0

Un type anonyme est généré par le compilateur et placé dans l'ensemble de sortie. Ils ne peuvent pas être générés dynamiquement au moment de l'exécution de la même manière. Maintenant, vous pouvez générer un tel type dynamiquement, mais je suis à peu près sûr qu'il ne fonctionnera pas correctement dans une expression LINQ que vous essayez de l'utiliser maintenant. –

+0

Avec quel fournisseur LINQ allez-vous utiliser ceci? LINQ aux objets? LINQ aux entités? Autre chose? – svick

+0

Qu'en est-il du type de retour de votre méthode? maintenant vous avez une expression retournant une chaîne, dans votre scénario souhaité, il retournerait un type anonyme? Ce n'est pas possible. À tout le moins, vous devrez modifier votre méthode pour modifier la requête au lieu de renvoyer l'expression de regroupement. Ensuite, vous pouvez générer les types à la volée avec IL, mais c'est un peu moche, pas si rapide, et vous devez gérer la mise en cache, et le nettoyage et beaucoup de bits sales :( – MBoros

Répondre

0

Si le type de la clé de regroupement n'a pas d'importance pour vous, vous pouvez créer des types dynamiquement et appeler le regroupement en fonction de ces types:

public static Expression<Func<TSource, object>> DynamicGroupBy<TSource> 
     (params string[] properties) 
{ 
    var entityType = typeof(TSource); 
    var props = properties.Select(x => entityType.GetProperty(x)).ToList(); 
    var source = Expression.Parameter(entityType, "x"); 

    // create x=> new myType{ prop1 = x.prop1,...} 
    var newType = CreateNewType(props); 
    var binding = props.Select(p => Expression.Bind(newType.GetField(p.Name), 
        Expression.Property(source, p.Name))).ToList(); 
    var body = Expression.MemberInit(Expression.New(newType), binding); 
    var selector = Expression.Lambda<Func<TSource, object>>(body, source); 
    return selector; 
} 
public static Type CreateNewType(List<PropertyInfo> props) 
{ 
    AssemblyName asmName = new AssemblyName("MyAsm"); 
    AssemblyBuilder dynamicAssembly = AssemblyBuilder 
     .DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run); 
    ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("MyAsm"); 
    TypeBuilder dynamicAnonymousType = dynamicModule 
     .DefineType("MyType", TypeAttributes.Public); 

    foreach (var p in props) 
    { 
     dynamicAnonymousType.DefineField(p.Name, p.PropertyType, FieldAttributes.Public); 
    } 
    return dynamicAnonymousType.CreateType(); 
} 

Notez que le groupe type de clé est object.

+0

Cela fonctionne pour GROUP BY et Select aussi CAVEAT: la colonne doit appartenir au type TSource, donc une colonne de naviagation/apparentée ie x.Column1.NestedColumn ne fonctionne pas. – GregJF