2010-06-06 31 views
3

在System.Linq.Dynamic中,有幾種方法可動態地形成Select,Where和其他Linq語句。但SelectMany沒有。以System.Linq.Dynamic的方式動態調用SelectMany

的選擇方法爲以下幾點:

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; 
    } 

我試圖修改上面的代碼,小時後的工作,我無法找到出路。

歡迎任何建議。

Ying

+0

SelectMany中的'selector',詳細表的名稱? – 2010-10-29 16:29:51

回答

6

已經爲我們的項目實施了這一項,請讓我知道它是否適合您!

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

它的工作原理! 謝謝你,luksan。 Ying – Ying 2010-06-09 10:20:58

+0

太棒了!修復一些像(字符串IEnumerable ) 例如:new [] {typeof(Type)} .AsQueryable()。SelectMany(「it.AssemblyQualifiedName」); 將resultType更改爲: 類型resultType = lambda.Body.Type.GetInterfaces()。Single(a => a.Name == typeof(IEnumerable <>)。Name).GetGenericArguments()[0]; – pil0t 2014-01-06 01:45:13

0

我現在用的是NWDB當我嘗試:

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

我得到一個錯誤,因爲CompanyNameCustomersOrders。所以它沒有看到這兩個對象的組合。 當我這樣做:

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

它返回所需的結果。

1

我添加了另一個SelectMany,它可以回退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))); 
    } 

我還需要弄清楚如何做到以下幾點使用動態,我們的目標是返回一個新的結果對象。

 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

使用示例在這裏:http://stackoverflow.com/questions/5996403/counting-percent-of-rows-with-category-out-of-total-number-of-rows-using-dynamic/6047324#6047324 – alpav 2011-05-18 19:02:29