How to create a dynamic LINQ join extension method

前端 未结 3 1476
难免孤独
难免孤独 2020-11-27 13:55

There was a library of dynamic LINQ extensions methods released as a sample with Visual Studio 2008. I\'d like to extend it with a join method. The code below fail

相关标签:
3条回答
  • 2020-11-27 14:12

    You can install the nuget package of System.Linq.Dynamic.Core - https://github.com/StefH/System.Linq.Dynamic.Core

    This has the join method implemented along with various other helper methods.

    Using this library you can do a simple join in the following the way

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

    in the result selector outer and inner are key words to access the result of the join.

    Using a key with multiple properties and/or selecting a result with multiple properties can be done in the following way

    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)

    0 讨论(0)
  • 2020-11-27 14:12

    Here is some sample code showing a join on multiple columns. Using a datatable and datarows you need to always access fields via the indexer.

      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 讨论(0)
  • 2020-11-27 14:28

    I've fixed it myself now. It was a schoolboy error passing too many parameters to the CreateQuery(... ) call. Paste the following code into the Dynamic.cs file within the DynamicQueryable class for a dynamic Join extension method. You can find the source for the DynamicQuery sample project at http://code.msdn.microsoft.com/csharpsamples.
    Enjoy.

        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 讨论(0)
提交回复
热议问题