1

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

下面是示例实体。

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); 

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

LINQ to Entities不支持指定的类型成员'Date'。仅支持初始化程序,实体成员和实体导航属性。

解决方法是使用DbFunctions.TruncateTime()表示为in this answer等。但是,这不会与System.Linq.Dynamic

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

感谢,

+0

凭啥不这项工作开箱?几乎每个软件项目都有这个要求。 – FizxMike

回答

4

您可以使用的方法从我的回答对Dynamic Linq + Entity Framework: datetime modifications for dynamic select,即后处理的查询表达式定制ExpressionVisitor和替换他们DbFunctions当量的不支持的方法。在这种特殊情况下,与DbFunctions.TruncateTime方法调用替换DateTime.Date属性:

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(); 
+0

谢谢,如果一切正常,我们会尝试实现这一点并标记为答案。 – lopezbertoni

+0

工程就像一个魅力!谢谢!! – lopezbertoni