为什么Linq on date range在组合查询上返回null,在单独的查询上工作正常

时间:2017-12-17 04:02:52

标签: c# sql entity-framework linq datetime

问题,同时过滤日期范围内的记录&使用LINQ匹配CityID时,查询在分2步写入时成功;但是,在组合成一个查询时失败了

如何重写LINQ查询,以便 - 它可以执行两个过滤器(即匹配Unhandled rejection ValidationError: College validation failed at new ValidationError (C:\MyProject\node_modules\mongoose\lib\error\validation.js:23:11) at model.Document.invalidate (C:\MyProject\node_modules\mongoose\lib\document.js:1629:32) at C:\MyProject\node_modules\mongoose\lib\document.js:1501:17 at validate (C:\MyProject\node_modules\mongoose\lib\schematype.js:733:7) at C:\MyProject\node_modules\mongoose\lib\schematype.js:778:11 at Array.forEach (<anonymous>) at SchemaString.SchemaType.doValidate (C:\MyProject\node_modules\mongoose\lib\schematype.js:738:19) at C:\MyProject\node_modules\mongoose\lib\document.js:1499:9 at _combinedTickCallback (internal/process/next_tick.js:131:7) at process._tickCallback (internal/process/next_tick.js:180:9) 并检索{{1}中的记录1}} 同一步以提高效果?

我让它分两步完成,

即。做一个

CityId

然后

date range

当我把它们组合起来时它失败了!!

var Step1 = db.weekRecord.Where(x => x.CityId == CityRecord.Id).ToList();

在查找其他SO answers之后,我尝试了这个 TruncateTime ...无法让它工作..

Step1.Where(x => x.date.Date >= fromDate.Date 
                 && x.date.Date <= toDate.Date)
     .ToList();

错误:

  

[NotSupportedException:指定的类型成员'Date'不是   LINQ to Entities支持。只有初始化者,实体成员和   支持实体导航属性。]
  System.Data.Entity.Core.Objects.ELinq.MemberAccessTranslator.TypedTranslate(ExpressionConverter   parent,MemberExpression linq)+452
  System.Data.Entity.Core.Objects.ELinq.TypedTranslator`1.Translate(ExpressionConverter   parent,Expression linq)+49

3 个答案:

答案 0 :(得分:1)

问题很混乱,但我认为问题是.Date。与linq2sql不同,实体框架无法将.Date转换为sql。但你可以像

那样重写它
var fromDateDate = fromDate.Date;
var toDateDate = toDate.Date;

var testQueryRecrods = db.weekRecord
                .Where(x => x.CityId == CityRecord.Id)
                .Where(x => DbFunctions.TruncateTime(x.date) >= fromDateDate
                         && DbFunctions.TruncateTime(x.date) <= toDateDate)
                .ToList();

它会起作用。到某一点。在这种情况下,EF产生的实际上是完全愚蠢的。与linq2sql不同,EF生成查询,这不是sargable(在我的情况下*)。它可以比必要的慢几千倍。我建议完全避免转换到日期:

var fromDateDate = fromDate.Date;
var toDateDate1 = toDate.Date.AddDays(1);

var testQueryRecrods = db.weekRecord
                .Where(x => x.CityId == CityRecord.Id)
                .Where(x => x.date >= fromDateDate 
                         && x.date < toDateDate1)
                .ToList(); 

正如@juharr指出的那样,当你拆分查询时,你会在服务器上运行前半部分,而后半部分作为对象的linq运行。在这种情况下.Date可以正常工作,但是你在上半部分下载的记录比你需要的多得多。

*日期时间类型可能是问题,也许它会更好用datetime2,我没有测试这个场景

答案 1 :(得分:0)

最好的建议是为此编写自己的LINQ扩展..

public static class ext
{
    //This extension compares one date to another... if you can call from Linq
    public static bool GreaterThan(this DateTime self, DateTime CompareDate
    {
    if (self.Year > CompareDate.Year) return true;

    else if ((self.Year == CompareDate.Year) && (self.Month > CompareDate.Month)
      return true;

    else if ((self.Year == CompareDate.Year) && (self.Month ==  CompareDate.Month)  && (self.Day > CompareDate.Day))
      return true;

    return false;
    }

}

答案 2 :(得分:0)

我认为除了使用DbFunctions.TruncateTime Linq to Entities之外别无选择。因为,SQL Server查询Linq to Entities应执行转换datetimedate,并且可以使用的最佳方法是DbFunctions.TruncateTime。我刚调试DbFunctions.TruncateTime转换,翻译的查询似乎是;

WHERE (convert (datetime2, convert(varchar(255), [Extent1].[CreationDate], 102) ,  102)) > @p__linq__0

如您所见,在执行对话时,此处存在冗余字符串对话。但是,EF会像SQL 'cast(CreationDate as date)'一样将日期时间转换为SQL中的日期。但事实并非如此。

所以,这里有两种选择。

1-如果你有一个非常庞大的表,性能受冗余字符串对话的影响,你应该在SQL中手动构建你的查询作为存储过程或类似的东西,并从上下文执行它。

2-如果你没有那样的性能考虑;只需使用DbFunctions.TruncateTime(x.date)

var testQueryRecrods = db.weekRecord
    .Where(x => x.CityId == CityRecord.Id)
    .Where(x => DbFunctions.TruncateTime(x.date) >= fromDate.Date && DbFunctions.TruncateTime(x.date) <= toDate.Date)
    .ToList();