2010-06-06 12 views
3

Dans System.Linq.Dynamic, il existe quelques méthodes pour former dynamiquement des instructions Select, Where et autres instructions Linq. Mais il n'y a pas de SelectMany.Pour appeler dynamiquement SelectMany à la manière de System.Linq.Dynamic

La méthode de Select est comme suit:

public static IQueryable Select(this IQueryable source, string selector, params object[] values) 
    { 
     if (source == null) throw new ArgumentNullException("source"); 
     if (selector == null) throw new ArgumentNullException("selector"); 
     LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, null, selector, values); 
     IQueryable result = source.Provider.CreateQuery(
      Expression.Call(
       typeof(Queryable), "Select", 
       new Type[] { source.ElementType, lambda.Body.Type }, 
       source.Expression, Expression.Quote(lambda))); 

     return result; 
    } 

J'ai essayé de modifier le code ci-dessus, après les heures de travail, je ne pouvais pas trouver un moyen de sortir.

Toutes les suggestions sont les bienvenues.

Ying

+0

Le 'sélecteur' du SelectMany, le nom de la table de détail? –

Répondre

6

déjà mis en oeuvre un pour notre projet, laissez-moi savoir si cela fonctionne pour vous!

public static IQueryable SelectMany(this IQueryable source, string selector, params object[] values) 
{ 
    if (source == null) 
     throw new ArgumentNullException("source"); 
    if (selector == null) 
     throw new ArgumentNullException("selector"); 

    // Parse the lambda 
    LambdaExpression lambda = 
     DynamicExpression.ParseLambda(source.ElementType, null, selector, values); 

    // Fix lambda by recreating to be of correct Func<> type in case 
    // the expression parsed to something other than IEnumerable<T>. 
    // For instance, a expression evaluating to List<T> would result 
    // in a lambda of type Func<T, List<T>> when we need one of type 
    // an Func<T, IEnumerable<T> in order to call SelectMany(). 
    Type inputType = source.Expression.Type.GetGenericArguments()[0]; 
    Type resultType = lambda.Body.Type.GetGenericArguments()[0]; 
    Type enumerableType = typeof(IEnumerable<>).MakeGenericType(resultType); 
    Type delegateType = typeof(Func<,>).MakeGenericType(inputType, enumerableType); 
    lambda = Expression.Lambda(delegateType, lambda.Body, lambda.Parameters); 

    // Create the new query 
    return source.Provider.CreateQuery(
     Expression.Call(
      typeof(Queryable), "SelectMany", 
      new Type[] { source.ElementType, resultType }, 
      source.Expression, Expression.Quote(lambda))); 
} 
+0

Cela fonctionne! Merci, luksan. Ying – Ying

+0

Excellent! Pour résoudre certains cas comme (chaîne comme IEnumerable ) Exemple: new [] {typeof (Type)} .AsQueryable(). SelectMany ("it.AssemblyQualifiedName"); Modifier le type de résultat en: Type resultType = lambda.Body.Type.GetInterfaces(). Unique (a => a.Name == typeof (IEnumerable <>). Nom) .GetGenericArguments() [0]; – pil0t

0

J'utilise le NWDB lorsque je tente:

var customerandorderquery = db.Customers .SelectMany(c => c.Orders.DefaultIfEmpty()).Select("new(CustomerId, CompanyName, OrderId)"); 

Je reçois une erreur car CompanyName est en Customers pas Orders. Donc, il ne voit pas la combinaison des deux objets. Quand je fais:

.SelectMany(c => c.Orders.DefaultIfEmpty(), (cus, ord) => new { CustomerId = cus.CustomerID, OrderId = ord.OrderID == null ? -1 : ord.OrderID }); 

Il renvoie le résultat souhaité.

1

J'ai ajouté un autre SelectMany qui retient un AnonymousType.

public static IQueryable SelectMany(this IQueryable source, string selector, string resultsSelector, params object[] values) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 
     if (selector == null) 
      throw new ArgumentNullException("selector"); 

     // Parse the lambda 
     LambdaExpression lambda = 
      DynamicExpression.ParseLambda(source.ElementType, null, selector, values); 

     // Fix lambda by recreating to be of correct Func<> type in case 
     // the expression parsed to something other than IEnumerable<T>. 
     // For instance, a expression evaluating to List<T> would result 
     // in a lambda of type Func<T, List<T>> when we need one of type 
     // an Func<T, IEnumerable<T> in order to call SelectMany(). 
     Type inputType = source.Expression.Type.GetGenericArguments()[0]; 
     Type resultType = lambda.Body.Type.GetGenericArguments()[0]; 
     Type enumerableType = typeof(IEnumerable<>).MakeGenericType(resultType); 
     Type delegateType = typeof(Func<,>).MakeGenericType(inputType, enumerableType); 
     lambda = Expression.Lambda(delegateType, lambda.Body, lambda.Parameters); 

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

     // Create the new query 
     return source.Provider.CreateQuery(
      Expression.Call(
       typeof(Queryable), "SelectMany", 
       new Type[] { source.ElementType /*TSource*/, /*,TCollection*/resultType /*TResult*/, resultsSelectorLambda.Body.Type}, 
       source.Expression, Expression.Quote(lambda), Expression.Quote(resultsSelectorLambda))); 
    } 

Je dois encore comprendre comment faire ce qui suit en utilisant Dynamic, le but est de retourner un nouvel objet résultat.

 var customerandorderflat = db.Customers 
      .SelectMany(c => c.Orders.SelectMany(o => o.Order_Details, 
        (ord, orddetail) => new 
         { 
          OrderID = ord.OrderID, 
          UnitPrice = orddetail.UnitPrice 
         }).DefaultIfEmpty(), 
       (cus, ord) => new 
       { 
        CustomerId = cus.CustomerID, 
        CompanyName = cus.CompanyName, 
        OrderId = ord.OrderID == null ? -1 : ord.OrderID, 
        UnitPrice = ord.UnitPrice 
       }); 
+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