为 linq 和实体框架编写扩展方法

Posted

技术标签:

【中文标题】为 linq 和实体框架编写扩展方法【英文标题】:Write an extensions method for linq and entity framework 【发布时间】:2021-11-05 01:40:27 【问题描述】:

我有一个奇怪的问题,通过提升一个非常旧的系统并将 10 年前的 nHibernate 替换为 EF。我在为搜索页面制定一些 linq 扩展时遇到了麻烦。 我要重构的是这个(这个代码行被多次使用或与其他类型的变体一起使用):

            if (searchCriteria.PlannedEndDateFrom.HasValue && searchCriteria.PlannedEndDateTo.HasValue)
            
                efquerable= efquerable.Where(d => searchCriteria.PlannedEndDateFrom < d.PlannedEndDate && d.PlannedEndDate > searchCriteria.PlannedEndDateTo);

            
            else if (searchCriteria.PlannedEndDateFrom.HasValue)
            
                efquerable= efquerable.Where(d => d.PlannedEndDate > searchCriteria.PlannedEndDateFrom);
            
            else if (searchCriteria.PlannedEndDateTo.HasValue)
            
                efquerable= efquerable.Where(d => d.PlannedEndDate < searchCriteria.PlannedEndDateTo);

            

这应该能够转移到我做这种检查的扩展......

       private static IQueryable<T> FilterOnCorrectSearchDateTime<T>(this IQueryable<T> efquerable, Expression<Func<T, DateTime>> datePropertyName, DateTime? dateFrom, DateTime? dateTo)
       
//Missing code

然后被称为像

EFquerable = EFquerable.FilterOnCorrectSearchDateTime<EntityObjectWithDatetimeproperty>(s=>s.PlannedEndDate ,searchCriteria.PlannedEndDateFrom,searchCriteria.PlannedEndDateTo);

对于如何解决这个问题有什么建议吗? 我坚持的是处理对发送到函数的属性的检查。如何将 Expression> datePropertyName 表述为 Where 函数的可用语句?在这次重构中我还有什么遗漏的吗? 我一直在使用 System.Linq.Dynamics,但这似乎不太好......

【问题讨论】:

【参考方案1】:

你可以像这样实现 IQueryable 扩展方法:

    public static IQueryable<T> FilterOnCorrectSearchDateTime<T>(this IQueryable<T> efquerable, Func<T,DateTime> datePropertyValue, DateTime? dateFrom, DateTime? dateTo)
    
        if (dateFrom.HasValue && dateTo.HasValue)
        
            return efquerable.Where(d => dateFrom.Value < datePropertyValue(d)
                                    && datePropertyValue(d) < dateTo.Value);
        
        else if (dateFrom.HasValue)
        
            return efquerable.Where(d => datePropertyValue(d) > dateFrom);
        
        else if (dateTo.HasValue)
        
            return efquerable.Where(d => datePropertyValue(d) < dateTo);
        

        return efquerable;
    

然后使用它:

var results =  
iQueryable.FilterOnCorrectSearchDateTime( 
      (entityObject)=> entityObject.YourDateTimeField,
      dateFrom,
      dateTo);

更新:

还有LINQKIT

可能对您有所帮助的软件包。但是,恕我直言,将整个事情实现为动态 SQL 语句,这就是您实际掌握的内容,这将是一个更好的整体解决方案。

【讨论】:

遗憾的是这个解决方案没有奏效。 EF 抱怨返回 efquerable.Where(d => dateFrom.Value 好吧,如果它已应用于 Iquerable 结果集 AFTER 将执行“主”查询,可以这么说。毕竟 EF 应该在隧道的尽头生成 SQL,并且有任务将所有这些逻辑转换为 SQL EF 显然没有兴趣。但是不要害怕,请看一下我的更新,它可能会有所帮助。

以上是关于为 linq 和实体框架编写扩展方法的主要内容,如果未能解决你的问题,请参考以下文章

ABP框架源码中的Linq扩展方法

.NET 6 带有实体框架的新 LINQ 功能

扩展方法和Enumerable

如何很好的使用Linq的Distinct方法

创建 Where 查询的 LINQ 扩展方法

等效于链式 LINQ 扩展方法调用中的 'let' 关键字的代码