c# - 如何使用表达式选择组中的第一行
问题描述
当同一张表用于处理具有相似内容的不同数据时,我有一项任务。我使用动态 linq 表达式从 sql 获取数据。对我来说最复杂的任务是根据一个字段选择不同的行。表之一是零件,我将其作为示例显示。
我需要从 db 中选择每个描述的第一部分。Sql请求是:
SELECT * FROM [Parts] WHERE [Id] IN (SELECT MIN([Id]) FROM[Parts] GROUP BY [Description])
LINQ 请求是:
queryable = queryable.GroupBy(r => r.Dewcription).Select(g => g.FirstOrDefault());
我应该将 LINQ 查询重写为表达式。我已经成功使用 GROUP BY: var grouped = queryable.GroupBy(SelectedField, type); // 使用
public static IQueryable GroupBy([NotNull] this IQueryable source, string Property, [NotNull] Type type)
{
PropertyInfo property = type.GetProperty(Property);
ParameterExpression parameter = Expression.Parameter(type, "r");
MemberExpression member = Expression.MakeMemberAccess(parameter, property);
LambdaExpression lambda = Expression.Lambda(member, parameter);
MethodCallExpression resultExpression = GroupByCall(source, lambda, property.PropertyType, type);
return source.Provider.CreateQuery(resultExpression);
}
// 按方法应用分组
public static MethodCallExpression GroupByCall([NotNull] IQueryable queryable, LambdaExpression predicate, Type typeKey, Type typeSource)
{
MethodInfo MethodGroupBy = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.First(m => m.Name.Equals("GroupBy", StringComparison.OrdinalIgnoreCase) && m.GetParameters().Length == 2).MakeGenericMethod(typeSource, typeKey);
Type QueryableType = typeSource.QueryableType();
return Expression.Call(null, MethodGroupBy, Expression.Convert(queryable.Expression, QueryableType), Expression.Quote(predicate));
}
// 获取要从 Queryable 转换的 Queryable 类型
public static Type QueryableType(this Type type)
{
var list = Activator.CreateInstance(typeof(List<>).MakeGenericType(type));
MethodInfo Method = typeof(Queryable).GetMethod(nameof(Queryable.AsQueryable), new[] { typeof(IEnumerable) });
var listAsQueryable = Method.Invoke(null, new[] { list });
return listAsQueryable.GetType();
}
下一步是为 .Select(g => g.FirstOrDefault()) 制作表达式。不能直接应用,因为分组实体的类型是未知的,分组的结果是IGrouping<string, object>,其中object实际上是我们在执行时知道的类型。我需要类似的东西:
var grouped = queryable.GroupBy(SelectedField, type).SelectGroupFirst(type);
public static IQueryable SelectGroupFirst([NotNull] this IQueryable source, [NotNull] Type type)
{
ParameterExpression parameter = Expression.Parameter(type, "r");
MemberExpression member = Expression.MakeMemberAccess(parameter, ...get enumerable...);
...apply First() or FirstOrDefault()...
LambdaExpression lambda = Expression.Lambda(member, parameter);
MethodCallExpression resultExpression = SelectCall(source, lambda, ...IGrouping<string, type>..., type);
return source.Provider.CreateQuery(resultExpression);
}
public static MethodCallExpression SelectCall(IQueryable queryable, LambdaExpression predicate, Type typeKey, Type typeSource)
{
if (queryable == null) return null;
var methods = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name.Equals("Select", StringComparison.OrdinalIgnoreCase));
MethodInfo MethodSelect = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.First(m => m.Name.Equals("Select", StringComparison.OrdinalIgnoreCase) && m.GetParameters().Length == 2).MakeGenericMethod(typeSource, typeKey);
return Expression.Call(null, MethodSelect, queryable.Expression, Expression.Quote(predicate));
}
我还没有找到动态进行 IGrouping<string, type> 类型定义、定义组枚举属性并访问它的方法。
替代方案可能是混合使用 SQL 和 LINQ 的方式。有没有办法将上述 sql 请求用于第一次选择行,并使用 LINQ 对其进行修改以进行分页和过滤?我还没有找到。
解决方案
推荐阅读
- javascript - 我希望 javascript 在页面中心弹出
- javascript - ASP,输入后聚焦文本框
- python - 如何使用python将一个变量放入另一个变量数组
- css - 混合混合模式似乎无法在边缘工作
- python - 使用 Discord.py 创建机器人时,如何让我的音乐机器人在观众离开时离开?
- flutter - 使文本在点击时出现
- c++ - C++ 构造函数需要一个“:”(冒号)
- python - 线程计时器对象未按预期工作
- reporting-services - 当报告中没有数据时,不应发送 SSRS 报告电子邮件订阅
- javascript - 设置状态方法似乎什么都不做。为什么?