【问题标题】:Dynamic LINQ OrderBy Date only on DateTime Object Entity Framework仅在 DateTime 对象实体框架上的动态 LINQ OrderBy Date
【发布时间】:2017-09-15 00:26:14
【问题描述】:

我目前正在使用Dynamic LINQ (original codeplex link) 库来实现动态搜索功能。我有一个要求,我需要 OrderBy 一个 DateTime? 字段,只考虑日期而不是时间。 我正在使用 EntityFramework 查询 SQL Azure 数据库。

这是示例实体。

public class SampleEntity
{
    public DateTime? DateCreated { get; set; }
    public bool Flag { get; set; }
}

这是查询数据库的代码。

var orderByString = "DateCreated.Value.Date asc, Flag"; //This is a dynamic string
var query = _context.Set<SampleEntity>().OrderBy(orderByString);

System.Linq.Dynamic 解析此表达式(“DateCreated.Value.Date”)没有问题,但由于 LINQ to Entities 不支持它,它会引发以下错误(这是可以理解的)。 请记住,这必须在 IQueryable (I can't use the answer from this post) 上工作,因为我需要在服务器端进行排序。

LINQ to Entities 不支持指定的类型成员“日期”。仅支持初始化器、实体成员和实体导航属性。

解决方案是使用DbFunctions.TruncateTime() 表达的in this answer 和其他。但是,这不适用于System.Linq.Dynamic

关于如何解决这个问题的任何想法。可能的解决方案是向数据库添加另一列,其中只有 DateCreated 的日期部分并查询该列。但是,我宁愿不这样做,并且正在寻找解决此问题的其他方法。 另一种方法是动态生成 lambda 表达式并返回 DbFunctions.TruncateTime,然后针对 DB 执行该表达式。 任何输入表示赞赏。

谢谢,

【问题讨论】:

  • 为什么这不能开箱即用?几乎每个软件项目都存在这一要求。

标签: c# entity-framework linq entity-framework-6 linq-to-entities


【解决方案1】:

您可以使用我对Dynamic Linq + Entity Framework: datetime modifications for dynamic select 的回答中的方法,即使用自定义ExpressionVisitor 对查询表达式进行后处理,并将不支持的方法替换为它们的DbFunctions 等效项。在这种特殊情况下,将DateTime.Date 属性替换为DbFunctions.TruncateTime 方法调用:

public static class QueryableExtensions
{
    public static IQueryable<T> BindDbFunctions<T>(this IQueryable<T> source)
    {
        var expression = new DbFunctionsBinder().Visit(source.Expression);
        if (expression == source.Expression) return source;
        return source.Provider.CreateQuery<T>(expression);
    }

    public static IQueryable BindDbFunctions(this IQueryable source)
    {
        var expression = new DbFunctionsBinder().Visit(source.Expression);
        if (expression == source.Expression) return source;
        return source.Provider.CreateQuery(expression);
    }

    class DbFunctionsBinder : ExpressionVisitor
    {
        protected override Expression VisitMember(MemberExpression node)
        {
            if (node.Expression != null && node.Expression.Type == typeof(DateTime) && node.Member.Name == "Date")
            {
                var dateValue = Expression.Convert(Visit(node.Expression), typeof(DateTime?));
                var methodCall = Expression.Call(typeof(DbFunctions), "TruncateTime", Type.EmptyTypes, dateValue);
                return Expression.Convert(methodCall, typeof(DateTime));
            }
            return base.VisitMember(node);
        }
    }
}

示例用法:

var orderByString = "DateCreated.Value.Date asc, Flag"; //This is a dynamic string
var query = _context.Set<SampleEntity>().OrderBy(orderByString).BindDbFunctions();

【讨论】:

  • 谢谢,如果一切正常,将尝试实施并标记为答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多