好的,我承认我还没有完全“获取”lambda表达式和LINQ表达式树;我正在做的很多事情就是切割和粘贴,看看哪些有效。我看了很多文档,但我还没有找到我的“啊哈”时刻。
据说......
我正在尝试动态地将GroupBy表达式添加到我的Linq表达式中。我跟着这个问题: Need help creating Linq.Expression to Enumerable.GroupBy
并尝试实施我在那里看到的内容。
首先,我有我的数据库的实体类,以及一个名为ObjCurLocViewNormalized的表
我有一个进行初始调用的方法,
public IQueryable<ObjCurLocViewNormalized> getLocations()
{
IQueryable<ObjCurLocViewNormalized> res = (from loc in tms.ObjCurLocViewNormalized
select loc);
return res;
}
所以我可以致电:
IQueryable<MetAmericanLinqDataModel.ObjCurLocViewNormalized> locations = american.getLocations();
到目前为止没问题。
现在,我希望按照任意列进行分组,并进行如下调用:
var grouped = locations.addGroupBy(childLocationFieldName);
现在,我有一个方法:
static public System.Linq.IQueryable<System.Linq.IGrouping<string, TResult>> addGroupBy<TResult>(this IQueryable<TResult> query, string columnName)
{
var providerType = query.Provider.GetType();
// Find the specific type parameter (the T in IQueryable<T>)
var iqueryableT = providerType.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), null).FirstOrDefault();
var tableType = iqueryableT.GetGenericArguments()[0];
var tableName = tableType.Name;
var data = Expression.Parameter(iqueryableT, "query");
var arg = Expression.Parameter(tableType, tableName);
var nameProperty = Expression.PropertyOrField(arg, columnName);
var lambda = Expression.Lambda<Func<TResult, string>>(nameProperty, arg);
var expression = Expression.Call(typeof(Enumerable),
"GroupBy",
new Type[] { tableType, typeof(string) },
data,
lambda);
var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg); // this is the line that produces the error I describe below
var result = query.GroupBy(predicate).AsQueryable();
return result;
}
所有这些编译好了,但是当我运行它时,我收到错误:
System.ArgumentException: Expression of type 'System.Collections.Generic.IEnumerable`1[System.Linq.IGrouping`2[System.String,MetAmericanLinqDataModel.ObjCurLocViewNormalized]]' cannot be used for return type 'System.String'
错误来自这一行:
var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg);
我正在复制并调整此代码,以便我在动态添加Where子句到表达式时所做的成功工作。所以我有点在黑暗中刺伤。
如果那里的任何人可以帮助阐明这一点,显然发布完整的工作代码并为我做所有的想法将是伟大的:),但如果你可以只是列出为什么这是错误的,或如何围绕这些概念包围我,这将是伟大的。如果你可以指出可以真正帮助弥合lambda表达式基础和构建动态表达式树之间差距的文档,那就太棒了。我的知识显然有很大漏洞,但我认为这些信息可能对其他人有用。
感谢大家的时间,当然如果我在其他地方找到答案,我会在这里发布。
再次感谢。
唐
答案 0 :(得分:2)
解决方案应该非常简单:
public static IQueryable<IGrouping<TColumn, T>> DynamicGroupBy<T, TColumn>(
IQueryable<T> source, string column)
{
PropertyInfo columnProperty = typeof(T).GetProperty(column);
var sourceParm = Expression.Parameter(typeof(T), "x");
var propertyReference = Expression.Property(sourceParm, columnProperty);
var groupBySelector = Expression.Lambda<Func<T, TColumn>>(propertyReference, sourceParm);
return source.GroupBy(groupBySelector);
}
假设这样的示例类:
public class TestClass
{
public string TestProperty { get; set; }
}
你这样调用它:
var list = new List<TestClass>();
var queryable = list.AsQueryable();
DynamicGroupBy<TestClass, string>(queryable, "TestProperty");
答案 1 :(得分:0)
要使其发挥作用,您需要做的就是:
static public IQueryable<IGrouping<TValue, TResult>> addGroupBy<TValue, TResult>(
this IQueryable<TResult> query, string columnName)
{
var providerType = query.Provider.GetType();
// Find the specific type parameter (the T in IQueryable<T>)
const object EmptyfilterCriteria = null;
var iqueryableT = providerType
.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), EmptyfilterCriteria)
.FirstOrDefault();
Type tableType = iqueryableT.GetGenericArguments()[0];
string tableName = tableType.Name;
ParameterExpression data = Expression.Parameter(iqueryableT, "query");
ParameterExpression arg = Expression.Parameter(tableType, tableName);
MemberExpression nameProperty = Expression.PropertyOrField(arg, columnName);
Expression<Func<TResult, TValue>> lambda = Expression.Lambda<Func<TResult, TValue>>(nameProperty, arg);
//here you already have delegate in the form of "TResult => TResult.columnName"
return query.GroupBy(lambda);
/*var expression = Expression.Call(typeof(Enumerable),
"GroupBy",
new Type[] { tableType, typeof(string) },
data,
lambda);
var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg); // this is the line that produces the error I describe below
var result = query.GroupBy(predicate).AsQueryable();
return result;*/
}
你会用以下方式称呼你:
var grouped = locations.addGroupBy<string, ObjCurLocViewNormalized>(childLocationFieldName);
第一个通用参数“string”我们用来说明你分组的元素类型。例如,您可以按“int”字段进行分组,方法调用将如下所示:
var grouped = locations.addGroupBy<int, ObjCurLocViewNormalized>(someFieldNameWithTheTypeOfInt);
修改强> 只是为了完成这个解决方案你的方式:
//return query.GroupBy(lambda);
MethodCallExpression expression = Expression.Call(typeof (Enumerable),
"GroupBy",
new[] { typeof(TResult), typeof(TValue) },
data,
lambda);
var result = Expression.Lambda(expression, data).Compile().DynamicInvoke(query);
return ((IEnumerable<IGrouping<TValue, TResult>>)result).AsQueryable();