2008-12-23 11 views
9

Une bibliothèque de méthodes d'extensions dynamiques LINQ a été libérée en tant qu'échantillon avec Visual Studio 2008. Je voudrais l'étendre avec une méthode de jointure. Le code ci-dessous échoue avec une exception de correspondance de paramètre à l'exécution. Où est le problème?Comment créer une méthode d'extension de jointure LINQ dynamique

public static IQueryable Join(this IQueryable outer, IEnumerable inner, 
           string outerSelector, string innerSelector, string resultsSelector, 
           params object[] values) 
{ 
    if (inner == null) 
     throw new ArgumentNullException("inner"); 
    if (outerSelector == null) 
     throw new ArgumentNullException("outerSelector"); 
    if (innerSelector == null) 
     throw new ArgumentNullException("innerSelector"); 
    if (resultsSelector == null) 
     throw new ArgumentNullException("resultsSelctor"); 

    LambdaExpression outerSelectorLambda = 
     DynamicExpression.ParseLambda(outer.ElementType, null, 
             outerSelector, values); 
    LambdaExpression innerSelectorLambda = 
     DynamicExpression.ParseLambda(inner.AsQueryable().ElementType, 
             null, innerSelector, values); 

    ParameterExpression[] parameters = new ParameterExpression[] { 
     Expression.Parameter(outer.ElementType, "outer"), 
     Expression.Parameter(inner.AsQueryable().ElementType, 
     "inner") 
    }; 
    LambdaExpression resultsSelectorLambda = 
     DynamicExpression.ParseLambda(parameters, null, 
             resultsSelector, values); 

    return outer.Provider.CreateQuery(
     Expression.Call(
      typeof(Queryable), "Join", new Type[] { 
       outer.ElementType, 
       inner.AsQueryable().ElementType, 
       outerSelectorLambda.Body.Type, 
       innerSelectorLambda.Body.Type, 
       resultsSelectorLambda.Body.Type 
      }, 
      outer.Expression, inner.AsQueryable().Expression, 
      Expression.Quote(outerSelectorLambda), 
      Expression.Quote(innerSelectorLambda), 
      Expression.Quote(resultsSelectorLambda)) 
     ); 
} 
+0

pourrait vous coller le message d'erreur exact? – Perpetualcoder

+0

Pouvez-vous poster un exemple d'utilisation de votre jointure. Je voudrais l'utiliser, mais je suis un tel greenhorn chez LINQ. Merci. – joe

Répondre

19

Je l'ai corrigé moi-même maintenant. C'était une erreur d'écolier en passant trop de paramètres à l'appel CreateQuery (...). Collez le code suivant dans le fichier Dynamic.cs dans la classe DynamicQueryable pour une méthode d'extension de jointure dynamique. Vous pouvez trouver la source de l'exemple de projet DynamicQuery au http://code.msdn.microsoft.com/csharpsamples.
Profitez-en.

public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values) 
    { 
     if (inner == null) throw new ArgumentNullException("inner"); 
     if (outerSelector == null) throw new ArgumentNullException("outerSelector"); 
     if (innerSelector == null) throw new ArgumentNullException("innerSelector"); 
     if (resultsSelector == null) throw new ArgumentNullException("resultsSelctor"); 

     LambdaExpression outerSelectorLambda = DynamicExpression.ParseLambda(outer.ElementType, null, outerSelector, values); 
     LambdaExpression innerSelectorLambda = DynamicExpression.ParseLambda(inner.AsQueryable().ElementType, null, innerSelector, values); 

     ParameterExpression[] parameters = new ParameterExpression[] { 
      Expression.Parameter(outer.ElementType, "outer"), Expression.Parameter(inner.AsQueryable().ElementType, "inner") }; 
     LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(parameters, null, resultsSelector, values); 

     return outer.Provider.CreateQuery(
      Expression.Call(
       typeof(Queryable), "Join", 
       new Type[] {outer.ElementType, inner.AsQueryable().ElementType, outerSelectorLambda.Body.Type, resultsSelectorLambda.Body.Type }, 
       outer.Expression, inner.AsQueryable().Expression, Expression.Quote(outerSelectorLambda), Expression.Quote(innerSelectorLambda), Expression.Quote(resultsSelectorLambda))); 
    } 


    //The generic overload. 
    public static IQueryable<T> Join<T>(this IQueryable<T> outer, IEnumerable<T> inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values) 
    { 
     return (IQueryable<T>)Join((IQueryable)outer, (IEnumerable)inner, outerSelector, innerSelector, resultsSelector, values); 
    } 
+0

Exemple d'utilisation est ici: http://stackoverflow.com/questions/5996403/counting-percent-of-rows-with-category-out-of-total-number-of-rows-using-dynamic/6047324#6047324 – alpav

+0

L'utilisation simple de ce code est la suivante: 'var résultat = myDbContext.Person .Join (myDbContext.Roles," nouveau (Id comme firstKey, SomeOtherId comme secondKey) "," nouveau (PersonId comme firstKey, AlternativeId comme secondKey) " , "new (interne comme r, externe comme p)"), notez que si elle est jointe sur plusieurs colonnes, vous devez nous "as [somekey]" si elles ne portent pas le même nom ou une erreur se produira. Aussi dans le sélecteur de résultat, vous utilisez les mots-clés "externe" et "interne" – user2945722

1

Voici quelques exemples de code montrant une jointure sur plusieurs colonnes. En utilisant une datatable et des données, vous devez toujours accéder aux champs via l'indexeur.

DataTable t1 = new DataTable(); 
    t1.Columns.Add("FundId", typeof(int)); 
    t1.Columns.Add("Date", typeof(DateTime)); 
    t1.Columns.Add("CodeA", typeof(string)); 
    t1.Rows.Add(1, new DateTime(2010, 01, 01), "A1"); 
    t1.Rows.Add(2, new DateTime(2010, 01, 01), "A2"); 
    t1.Rows.Add(3, new DateTime(2010, 01, 01), "A3"); 

    DataTable t2 = new DataTable(); 
    t2.Columns.Add("FundId", typeof(int)); 
    t2.Columns.Add("Date", typeof(DateTime)); 
    t2.Columns.Add("CodeB", typeof(string)); 
    t2.Rows.Add(1, new DateTime(2010, 01, 01), "B1"); 
    t2.Rows.Add(2, new DateTime(2010, 01, 01), "B2"); 
    t2.Rows.Add(3, new DateTime(2010, 01, 01), "B3"); 

    IQueryable outerTable = t1.AsEnumerable().AsQueryable(); 
    IEnumerable innerTable = t2.AsEnumerable(); 

    var query = outerTable.Join 
    (
     innerTable, 
     "new(get_Item(0) as FundId, get_Item(1) as Date)", 
     "new(get_Item(0) as FundId, get_Item(1) as Date)", 
     "new(outer.get_Item(0) as FundId, outer.get_Item(2) as CodeA, inner.get_Item(2) as CodeB)" 
    ); 
+0

Cela ne répond pas à la question. Ici vous utilisez la méthode Join fournie par Linq, la question - était de créer cette méthode, car elle n'était pas encore fournie par Linq. – psycho

2

Vous pouvez installer le package NuGet de System.Linq.Dynamic.Core - https://github.com/StefH/System.Linq.Dynamic.Core

Cela a mis en œuvre la méthode join ainsi que diverses autres méthodes d'assistance.

En utilisant cette bibliothèque, vous pouvez faire un simple rejoindre dans ce qui suit le chemin

myContext.TableA.Join(myContext.TableB,'Id','TableAId','outer',null)

dans le sélecteur de résultat outer et inner sont des mots clés pour accéder au résultat de la jointure.

aide d'une clé avec des propriétés multiples et/ou la sélection d'un résultat avec plusieurs propriétés peut être fait de la manière suivante

myContext.TableA.Join(myContext.TableB,'new (Id as key1,Code as key2)','new (TableAId as key1,AnotherCol as key2)','new(outer.Id,inner.Desc)',null)

Questions connexes