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);
    }
}
posted @   a1010  阅读(179)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示