group and select works to an extent.

This commit is contained in:
David Lebée 2018-03-13 21:01:21 -05:00
parent 30d1d9072b
commit e4ce956d8a
4 changed files with 120 additions and 19 deletions

View File

@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PoweredSoft.DynamicLinq;
using PoweredSoft.DynamicLinq.Dal;
namespace PoweredSoft.DynamicLinq.Test
{
@ -72,31 +73,42 @@ namespace PoweredSoft.DynamicLinq.Test
int i = 0;*/
/*
.Select(t => new
var dynamicSyntax3 = TestData.Sales
.AsQueryable()
.GroupBy(t => t.ClientId)
.Select(t => new
{
TheClientId = t.Key,
Count = t.Count(),
});*/
BlogContext bc = null;
if (bc != null)
{
TheClientId = t.Key,
Count = t.Count(),
CountClientId = t.Count(t2 => t2.ClientId > 1),
LongCount = t.LongCount(),
NetSales = t.Sum(t2 => t2.NetSales),
TaxAverage = t.Average(t2 => t2.Tax),
Sales = t.ToList()
});*/
bc.Authors.GroupBy(t => new { t.LastName }).Select(t => new
{
t.Key.LastName,
Count = t.Count()
});
}
var dynamicSyntax2 = TestData.Sales
.AsQueryable()
.GroupBy(t => t.Path("ClientId"))
.Select(t =>
{
t.Key("TheClientId", "ClientId");
t.Count("Count");
t.Key("TheClientId", "ClientId");
t.Count("Count");
/*
t.LongCount("LongCount");
t.Sum("NetSales");
t.Average("Tax", "TaxAverage");
t.ToList("Sales");
t.ToList("Sales");*/
});
var result = dynamicSyntax2.ToObjectList();
}
private object compare(MockSale arg)

View File

@ -96,7 +96,27 @@ namespace PoweredSoft.DynamicLinq
if (sb.Empty)
throw new Exception("No select specified, please specify at least one select path");
return query;
return QueryableHelpers.Select(query,
sb.Parts.Select(t => (selectType: t.SelectType, propertyName: t.PropertyName, path: t.Path)).ToList(),
sb.DestinationType);
}
public static List<object> ToObjectList(this IQueryable query)
{
var ret = new List<object>();
foreach (var o in query)
ret.Add(o);
return ret;
}
public static List<dynamic> ToDynamicList(this IQueryable query)
{
var ret = new List<dynamic>();
foreach (var o in query)
ret.Add(o);
return ret;
}
}
}

View File

@ -15,7 +15,7 @@ namespace PoweredSoft.DynamicLinq.Fluent
public class SelectBuilder
{
public List<SelectPart> Parts = new List<SelectPart>();
public Type DestinationType { get; set; }
public bool Empty => Parts?.Count == 0;
protected void throwIfUsedOrEmpty(string propertyName)

View File

@ -5,14 +5,15 @@ using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace PoweredSoft.DynamicLinq.Helpers
{
public static class QueryableHelpers
{
public static Expression GetConditionExpressionForMember(ParameterExpression parameter, Expression member, ConditionOperators conditionOperator, ConstantExpression constant, StringComparison? stringComparision)
{
if (parameter == null)
@ -106,8 +107,8 @@ namespace PoweredSoft.DynamicLinq.Helpers
var result = query.Provider.CreateQuery(groupByExpression);*/
var ctor = Expression.New(keyType);
var bindings = partExpressions.Select(partExpression => Expression.Bind(keyType.GetProperty(partExpression.propertyName), partExpression.expression)).ToList();
var mi = Expression.MemberInit(ctor, bindings.ToArray());
var bindings = partExpressions.Select(partExpression => Expression.Bind(keyType.GetProperty(partExpression.propertyName), partExpression.expression)).ToArray();
var mi = Expression.MemberInit(ctor, bindings);
var lambda = Expression.Lambda(mi, parameter);
var genericMethod = equalityCompareType == null ? Constants.GroupByMethod.MakeGenericMethod(type, keyType) : Constants.GroupByMethodWithEqualityComparer.MakeGenericMethod(type, keyType); //, Activator.CreateInstance(equalityCompareType));
var groupByExpression = equalityCompareType == null ? Expression.Call(genericMethod, query.Expression, lambda) : Expression.Call(genericMethod, query.Expression, lambda, Expression.New(equalityCompareType));
@ -115,6 +116,72 @@ namespace PoweredSoft.DynamicLinq.Helpers
return result;
}
public static IQueryable Select(IQueryable query, List<(SelectTypes selectType, string propertyName, string path)> parts, Type destinationType = null)
{
// create parameter.
var queryType = query.ElementType;
var parameter = Expression.Parameter(queryType, "t");
// establish which anynomous types we might need to create.
var fields = new List<(Type type, string propertyName)>();
var partExpressions = new List<(Expression expression, string propertyName)>();
parts.ForEach(part =>
{
var partBodyExpression = CreateSelectExpression(query, parameter, part.selectType, part.path);
fields.Add((partBodyExpression.Type, part.propertyName));
partExpressions.Add((partBodyExpression, part.propertyName));
});
// type to use.
var typeToCreate = destinationType ?? DynamicClassFactory.CreateType(fields);
var ctor = Expression.New(typeToCreate);
var bindings = partExpressions.Select(t => Expression.Bind(typeToCreate.GetProperty(t.propertyName), t.expression)).ToArray();
var mi = Expression.MemberInit(ctor, bindings);
var lambda = Expression.Lambda(mi, parameter);
/*
public static IQueryable<TypeTwo> Tester(IQueryable<TypeOne> data)
{
var source = Expression.Parameter(typeof(TypeOne), "source");
var selector = Expression.Lambda<Func<TypeOne, TypeTwo>>(
Expression.MemberInit(Expression.New(typeof(TypeTwo)),
Expression.Bind(typeof(TypeTwo).GetProperty("TwoProp"), Expression.Property(source, "OneProp"))),
source);
return data.Select(selector);
}*/
//public static IQueryable<TResult> Select<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector);
var selectExpr = Expression.Call(typeof(Queryable), "Select", new[] { query.ElementType, typeToCreate }, query.Expression, lambda);
var result = query.Provider.CreateQuery(selectExpr);
return result;
}
private static Expression CreateSelectExpression(IQueryable query, ParameterExpression parameter, SelectTypes selectType, string path)
{
if (selectType == SelectTypes.Key)
{
return ResolvePathForExpression(parameter, path);
}
else if (selectType == SelectTypes.Count)
{
// TODO: check if we need to ensure if grouped before getting second generic argument.
var notGroupedType = parameter.Type.GenericTypeArguments[1];
var body = Expression.Call(typeof(Enumerable), "Count", new[] { notGroupedType }, parameter);
return body;
}
else if (selectType == SelectTypes.LongCount)
{
// TODO: check if we need to ensure if grouped before getting second generic argument.
var notGroupedType = parameter.Type.GenericTypeArguments[1];
var body = Expression.Call(typeof(Enumerable), "LongCount", new[] { notGroupedType }, parameter);
return body;
}
throw new NotSupportedException($"unkown select type {selectType}");
}
public static IQueryable GroupBy(IQueryable query, Type type, string path)
{
var parameter = Expression.Parameter(type, "t");
@ -327,6 +394,8 @@ namespace PoweredSoft.DynamicLinq.Helpers
throw new NotSupportedException($"{collectionHandling} is not supported");
}
public static Expression<Func<T, bool>> CreateFilterExpression<T>(string path,
ConditionOperators condition,
object value,