我们正在研究一个使用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扩展方法。我们现在只需要一个概念。
谢谢您!