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

时间:2018-07-11 19:18:12

标签: c# sql-server entity-framework entity-framework-6

我们正在研究使用EF6 / MSSQL的解决方案,在该解决方案中,我们可以根据用户查询输入(例如5分钟四舍五入,10等)对日期/时间进行四舍五入

查询示例为:

(这只是模型,并不代表任何功能)

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

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

我想我将用VisitMethodCall实现一个ExpressionVisitor,并在请求RoundToNearest方法时应用我的Expression,但是我似乎做不到。

我们正在动态建立查询,因此我们可以使用聚合(分组依据等)。上面的用法仅用于概念证明。

如果我们想使用扩展方法将自己的公式添加到列中,这将转换为SQL表达式,我们该怎么做?

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

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

其中显示的5.0值将是传递给扩展方法的TimeSpan上TotalMinutes的十进制值。

此刻,我出错了:

  

抛出异常:mscorlib.dll中的'System.NotSupportedException'   LINQ to Entities无法识别方法'System.DateTime RoundToNearest(System.DateTime,System.TimeSpan)'方法,并且该方法无法转换为商店表达式。

注意:

  • 我们不想在内存中执行此过程。我们正在一次调用中处理数百万条记录,并希望将其保存在SQL服务器上
  • 我们已经为其他功能(如AddHours,AddMinutes等)实现了ExpressionVisitor,效果很好。我们现在正在寻求扩展它以返回表达式。
  • 除非我们可以将Extension方法作为Expression的一部分映射到它,否则我们对使它成为Sql函数不感兴趣。
  • 如果您有一个更好的想法可以舍入日期/时间而不在​​内存中进行,请开放想法。完成后,我们将创建RoundDown,RoundNearest,RoundUp扩展方法。我们现在只需要一个概念即可。

谢谢!

0 个答案:

没有答案