代码之家  ›  专栏  ›  技术社区  ›  TravisWhidden

实体框架6-应用自定义SQL表达式选择要执行的SQL列

  •  1
  • TravisWhidden  · 技术社区  · 6 年前

    我们正在研究一个使用EF6/MSSQL的解决方案,在这个解决方案中,我们可以根据用户的查询输入(例如,5分钟取整、10等)来取整日期/时间

    查询示例如下:

    from item in context.MyView 
    select item.DataTimeStamp.RoundToNearest(TimeSpan.FromMinutes(5))
    

    显然,RoundToNearest(TimeSpan)不存在,并且与实体框架不兼容。

    我们正在动态地构建查询,因此可以使用聚合(groupby等)。上面的用法只是为了证明概念。

    到目前为止我所拥有的(当然不起作用)

    public static DateTime RoundToNearest(this DateTime date, TimeSpan period)
        {
            throw new NotSupportedException("This method should not be called directly. This will be called by an expression visitor");
        }
    
    
    class DbFunctionsBinder : ExpressionVisitor
    {
          protected override Expression VisitMethodCall(MethodCallExpression node)
          {
               if (node.Object == null || node.Object.Type != typeof(DateTime)) return base.VisitMethodCall(node);
    
               switch (node.Method.Name)
               {
                   case nameof(RoundToNearest):
                       return Expr((DateTime timeValue, TimeSpan roundValue) => timeValue.Date)  // Code Later 
                       .WithParameters(Visit(node.Object), Visit(node.Arguments[0]));
               }
               return base.VisitMethodCall(node);
           }
    }
    

    一旦我得到它,我将从下面的SQL语句中创建等价的表达式:

    select top 10000
    (
        CAST(
            -- Round with Truncate Round(value,0,1)
            ROUND(
                CAST(DataTimeStamp AS FLOAT) * (1440/5.0),0,1)/(1440/5.0) 
            as Datetime)
     ) as TheRoundedTime 
    from DataSourceTable
    

    引发异常:'System.NotSupportedException异常'在mscorlib.dll

    笔记:

    • 我们已经为AddHours、AddMinutes等其他功能实现了ExpressionVisitor,这些功能非常有效。我们现在要扩展它以返回一个表达式。
    • 如果你有一个更好的方法来舍入日期/时间,而不是在内存中进行,那就敞开心扉吧。一旦完成,我们将创建一个RoundDown,RoundNearest,RoundUp扩展方法。我们现在只需要一个概念。

    谢谢您!

    0 回复  |  直到 6 年前