V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yuhangch
V2EX  ›  .NET

EF Core LINQ 使用反射获取属性值大幅降低查询速度

  •  
  •   yuhangch · 2022-04-11 20:13:19 +08:00 · 2432 次点击
    这是一个创建于 717 天前的主题,其中的信息可能已经有所发展或是发生改变。

    多个表,不同的字段,一个业务他们处理逻辑相同

    所以想用反射来减少点代码量,但是使用反射来获取值速度下降的厉害 ~ x5

    async List<object> SelectValues<T>(IQueryable<T> queryable, string fieldName)
                where T : class
    {
        var type = typeof(T);
        var field = type.GetProperty(fieldName);
        if (field == null) throw new ArgumentNullException(nameof(fieldName));
        var get = (T a) => (double?) field.GetValue(a); 
        return queryable
        	.Select(t => new {
            	V = get(t)   //非常慢
             // V = t.field  速度正常 
            }).ToList();
    }
    

    有没有什么优化方案,或者不应该这么干?

    10 条回复    2022-04-12 09:43:14 +08:00
    leeg810312
        1
    leeg810312  
       2022-04-11 20:25:54 +08:00 via Android
    在集合循环执行反射不合适,可以替换 fieldname 参数为 lambda 表达式参数
    hackfly
        2
    hackfly  
       2022-04-11 20:47:50 +08:00
    定义一个泛型类,定义一个查询接口,每个表类派生,都实现各自查询接口,这样也多不了多少代码,就是多几个实力类
    moen
        3
    moen  
       2022-04-11 21:08:27 +08:00
    GetProperty/GetValue 这一套下来慢是必然的。一种解决方案就是使用表达式树,生成一个获取 t.prop 的委托;第二种就是使用 Source Generator 把用到的 T 的所有属性的获取代码都生成出来,0 反射
    killergun
        4
    killergun  
       2022-04-11 21:11:39 +08:00
    你看看官方的集合扩展 Select 是怎么实现的,根本就不需要反射
    userforg2021
        5
    userforg2021  
       2022-04-11 21:55:24 +08:00
    你这个需求。。。不就是 Select 的功能吗。。。。
    Rocketer
        6
    Rocketer  
       2022-04-11 23:09:07 +08:00
    t.field 会被直接翻译成 sql 语句在数据库中执行,而反射只能把数据先取到内存中,转化成对象,再反射取值,当然慢。

    更何况反射本身就慢。

    你这个需求,可以使用 Dynamic LINQ 来替换 Select 里面的内容,从而使操作能最终变成 sql 语句。

    官方例子就有: https://dynamic-linq.net/basic-simple-query
    beginor
        7
    beginor  
       2022-04-11 23:24:06 +08:00
    这个只需要对 Linq 做一点儿扩展就够,就是构建简单的取属性的 lambda 表达式传进去就行了, 甚至都不需要第三方类库, 给你看一个动态添加排序的例子

    https://github.com/beginor/appfx/blob/master/src/Core/LinqExtensions.cs#L64
    ShareDuck
        8
    ShareDuck  
       2022-04-12 09:04:04 +08:00
    调用的时候,同样都要输入 fieldName ,也没有降低代码量吧。
    coder001
        9
    coder001  
       2022-04-12 09:22:02 +08:00
    在 IQueryable<T>用 AutoMapper 的 Projection 方法,可以生成查询表达式实现按需 Select
    yuhangch
        10
    yuhangch  
    OP
       2022-04-12 09:43:14 +08:00
    @leeg810312
    @hackfly
    @moen
    @killergun
    @userforg2021
    @Rocketer
    @beginor
    感谢各位,先用 dynamic linq 顶一下,后面有时间了再看看表达式树的方法
    (头天晚上焦头烂额,发个帖第二天早上解决了,v 站 up
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1131 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 18:44 · PVG 02:44 · LAX 11:44 · JFK 14:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.