首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实体框架+ DayOfWeek

实体框架+ DayOfWeek
EN

Stack Overflow用户
提问于 2016-10-26 20:29:31
回答 1查看 4.5K关注 0票数 5

使用System.Linq.Dynamic (在这里托管的https://github.com/kahanu/System.Linq.Dynamic ),我试图捕获在DateTime上找到的DayOfWeek字段,以便使用实体框架6(或更高版本)进行聚合。

以前要求类似的东西,这很有帮助,动态Linq +实体框架:用于动态选择的日期时间修改

实体框架支持使用

代码语言:javascript
复制
SqlFunctions.DatePart("dw", datetime?)

或者我们可以做一些更想做的事情,比如

代码语言:javascript
复制
DbFunctions.DiffDays(date?, date?).  

想法:

将Linq中的DayOfWeek获取到实体

我发现这非常有趣,我喜欢它,因为它不使用SqlFunctions,这可能使我只限于Server。此外,开发人员可以控制一周的第一天是什么,而不必查询Server属性来查找其配置方式(对于第一天)。

出于实验目的,我一直试图在VisitMember()覆盖中实现这一点:

代码语言:javascript
复制
protected override Expression VisitMember(MemberExpression node)
{
     if (node.Type == typeof(System.DayOfWeek))
     {
          var firstSunday = new DateTime(1753, 1, 7);

                var firstSundayExpression = Expression.Constant(firstSunday, typeof(DateTime?));
                var timeValue = node.Expression;
                if (timeValue.Type != typeof(DateTime?)) timeValue = Expression.Convert(timeValue, typeof(DateTime?));
                var methodCall = Expression.Call(
                              typeof(DbFunctions), "DiffDays", Type.EmptyTypes, firstSundayExpression, timeValue);
                return Expression.Convert(methodCall, typeof(int?));
      }

      return base.VisitMember(node);
 }

用上面的想法,我想我可以把这个表达式包装起来,然后把模数值应用到输入时间上,但是我甚至不能让这个表达式更进一步。

我觉得我缺少表达方式的一个基本部分。我所犯的错误

参数类型不匹配 在System.Linq.Expressions.Expression.Bind(MemberInfo成员,表达式表达式) 在System.Linq.Expressions.ExpressionVisitor.VisitT 在System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression节点) 在System.Linq.Expressions.ExpressionVisitor.VisitLambdaT 在System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression节点) (在System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider节点) 在System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression节点) (在QueryableExtensions.DbFunctionsBinder.VisitMethodCall(MethodCallExpression节点)在Path\QueryableExtensions.cs:line 48中 在BindDbFunctions(IQueryable源代码)在Path\QueryableExtensions.cs:line 13 在AggregateHelper.d__15.MoveNext()中的Path\AggregateHelper.cs:line 811 -从抛出异常的以前位置开始的堆栈跟踪的结束 (在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task任务) (在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task任务) 在System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 在AggregationPluginServiceHelper.d__9.MoveNext() ( Path\AggregationPluginServiceHelper.cs:line 199 )

我知道我能做到这一点,我写的查询是内联编译的。效果很好。但是这是专门使用动态库的。

示例用法将是:

代码语言:javascript
复制
var grouping = select.GroupBy("new (DateTimeColumn.DayOfWeek)", "it");

有更好的方法来获得一周中的一天吗?我知道这可能是不同的文化,所以做模数不同的周日(链接想法以上),我相信是正确的方法。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-26 21:17:27

所以你基本上需要转换一个表达式,比如

代码语言:javascript
复制
expr.DayOfWeek

代码语言:javascript
复制
var firstSunday = new DateTime(1753, 1, 7);
(DayOfWeek)(((int)DbFunctions.DiffDays((DateTime?)firstSunday, (DateTime?)expr)) % 7)

以下是你如何做到这一点:

代码语言:javascript
复制
protected override Expression VisitMember(MemberExpression node)
{
    if (node.Type == typeof(DayOfWeek))
    {
        var expr = node.Expression;
        var firstSunday = new DateTime(1753, 1, 7);
        var diffDays = Expression.Convert(
            Expression.Call(
                typeof(DbFunctions), "DiffDays", Type.EmptyTypes,
                Expression.Constant(firstSunday, typeof(DateTime?)),
                Expression.Convert(expr, typeof(DateTime?))),
            typeof(int));
        var dayOfWeek = Expression.Convert(
            Expression.Modulo(diffDays, Expression.Constant(7)),
            typeof(DayOfWeek));
        return dayOfWeek;
    }
    return base.VisitMember(node);
}

更新:过程可以通过使用编译时原型表达式来简化,使用小助手实用程序将参数替换为实际值:

代码语言:javascript
复制
public static class ExpressionUtils
{
    public static Expression<Func<T, TResult>> Expr<T, TResult>(Expression<Func<T, TResult>> e) => e;
    public static Expression<Func<T1, T2, TResult>> Expr<T1, T2, TResult>(Expression<Func<T1, T2, TResult>> e) => e;
    public static Expression<Func<T1, T2, T3, TResult>> Expr<T1, T2, T3, TResult>(Expression<Func<T1, T2, T3, TResult>> e) => e;
    public static Expression<Func<T1, T2, T3, T4, TResult>> Expr<T1, T2, T3, T4, TResult>(Expression<Func<T1, T2, T3, T4, TResult>> e) => e;
    public static Expression WithParameters(this LambdaExpression expression, params Expression[] values)
    {
        return expression.Parameters.Zip(values, (p, v) => new { p, v })
            .Aggregate(expression.Body, (e, x) => e.ReplaceParameter(x.p, x.v));
    }
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
    {
        return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
    }
    class ParameterReplacer : ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == Source ? Target : base.VisitParameter(node);
        }
    }
}

这与C#6静态导入特性相结合,使实现变得更加简单和可读性。

例如:

代码语言:javascript
复制
using static System.Linq.Expressions.Expression;
using static ExpressionUtils;

现在所讨论的方法如下所示:

代码语言:javascript
复制
protected override Expression VisitMember(MemberExpression node)
{
    if (node.Type == typeof(DayOfWeek))
    {
        return Expr((DateTime dateValue1, DateTime dateValue2) => 
            (DayOfWeek)(DbFunctions.DiffDays(dateValue1, dateValue2).Value % 7))
            .WithParameters(Constant(new DateTime(1753, 1, 7)), Visit(node.Expression));
    }
    return base.VisitMember(node);
}

还有你上一个关于AddHours的问题

代码语言:javascript
复制
protected override Expression VisitMethodCall(MethodCallExpression node)
{
    if (node.Object != null && node.Object.Type == typeof(DateTime))
    {
        if (node.Method.Name == "AddHours")
        {
            return Expr((DateTime timeValue, double addValue) => 
                DbFunctions.AddHours(timeValue, (int)addValue).Value)
                .WithParameters(Visit(node.Object), Visit(node.Arguments[0]));
        }
    }
    return base.VisitMethodCall(node);
}
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40271588

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档