c#通过表达式树优雅的实现分组取TopN笔记
需要引入nuget包来实现ef.functions调用row_number
1 | Thinktecture.EntityFrameworkCore.SqlServer |
调用方式:
1 2 3 4 | //顺排 context.Table.GroupBySortTop(1, x => x.partitionProptery, x => x.orderByProperty).ToList() //倒排 context.Table.GroupBySortTopDescending(1, x => x.partitionProptery, x => x.orderByProperty).ToList() |
核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | public class GroupBySorting<T> { public T Data { get ; set ; } public long Rowid { get ; set ; } } public static class Extension { static string OrderBy = nameof(RelationalDbFunctionsExtensions.OrderBy); static string OrderByDescending = nameof(RelationalDbFunctionsExtensions.OrderByDescending); static MethodInfo RowNumber = typeof (RelationalDbFunctionsExtensions).GetMethods().FirstOrDefault(x => x.IsGenericMethod && x.Name == nameof(RelationalDbFunctionsExtensions.RowNumber)); static Dictionary< string , MethodInfo> OrderMethods = new List<( string , MethodInfo)>() { new (OrderBy, typeof (RelationalDbFunctionsExtensions).GetMethod(OrderBy)), new (OrderByDescending, typeof (RelationalDbFunctionsExtensions).GetMethod(OrderByDescending)) }.ToDictionary(x => x.Item1, x => x.Item2); static IQueryable<T> GroupBySortTop<T, T1, T2>( this IQueryable<T> source, int limit, Expression<Func<T, T1>> partitionByExpression, Expression<Func<T, T2>> orderByExpression, string orderBy) { var prm = Expression.Parameter( typeof (T)); var constFunc = Expression.Constant(EF.Functions); var orderFunc = Expression.Call( null , OrderMethods[orderBy].MakeGenericMethod( typeof ( int )), constFunc, Expression.Property(prm, (orderByExpression.Body as MemberExpression).Member.Name)); var expressions = Expression.Call( null , RowNumber.MakeGenericMethod( typeof (T1)), constFunc, Expression.Property(prm, (partitionByExpression.Body as MemberExpression).Member.Name), orderFunc); var targetType = typeof (GroupBySorting<T>); var memberBindings = new List<MemberBinding>(); memberBindings.Add(Expression.Bind(targetType.GetProperty(nameof(GroupBySorting<T>.Data)), prm)); memberBindings.Add(Expression.Bind(targetType.GetProperty(nameof(GroupBySorting<T>.Rowid)), expressions)); var initmember = Expression.MemberInit(Expression.New( typeof (GroupBySorting<T>)), memberBindings); var lambda = Expression.Lambda<Func<T, GroupBySorting<T>>>(initmember, prm); return source.Select(lambda).AsSubQuery().Where(x => x.Rowid <= limit).Select(x => x.Data); } public static IQueryable<T> GroupBySortTop<T, T1, T2>( this IQueryable<T> source, int limit, Expression<Func<T, T1>> partitionByExpression, Expression<Func<T, T2>> orderByExpression) { return GroupBySortTop(source, limit, partitionByExpression, orderByExpression, OrderBy); } public static IQueryable<T> GroupBySortTopDescending<T, T1, T2>( this IQueryable<T> source, int limit, Expression<Func<T, T1>> partitionByExpression, Expression<Func<T, T2>> orderByExpression) { return GroupBySortTop(source, limit, partitionByExpression, orderByExpression, OrderByDescending); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?