DateTime.Month上的Where子句

本文关键字:子句 Where 上的 Month DateTime | 更新日期: 2023-09-27 18:24:13

情况如下:

我正在为一个有点大的实体做一个基本的搜索。目前,结果的数量是可控的,但我预计在使用一两年后会有大量数据,因此性能在这里很重要。

我正在浏览的对象有一个DateTime值,我需要能够输出具有相同月份的所有对象,而不考虑年份。有多个搜索字段可以组合,但其他字段不会在此处造成问题。

我试过这个:

if(model.SelectedMonth != null)
{
    contribs = contribs.Where(x => x.Date.Value.Month == model.SelectedMonth);
}
model.Contribs = contribs
    .Skip(NBRESULTSPERPAGE*(model.CurrentPage - 1))
    .Take(NBRESULTSPERPAGE)
    .ToList();

到目前为止,我得到的只是"无效的where条件。一个实体成员正在调用一个无效的属性或方法。"。我正在寻找一种干净的方法来完成这项工作。

DateTime.Month上的Where子句

你说:

我正在浏览的对象有一个DateTime值,我需要能够输出具有相同月份的所有对象,而不考虑的年份

我预计在使用一两年后会有大量的数据,因此性能在这里很重要。

就在那里,你有一个问题。我知道你正在使用LINQ to CRM,但无论你使用什么技术,这个问题实际上都会出现。

根本问题是日期和时间存储在一个字段中。年、月、日、小时、分钟、秒和小数秒都打包成一个整数,表示某个时间以来的单位数。在.NET中的DateTime的情况下,这是自1/1/0001以来的刻度数。如果该值存储在SQL DateTime2字段中,则情况相同。其他数据类型具有不同的开始日期(时期)和不同的精度。但在所有情况下,内部只有一个数字。

如果您搜索的值是在特定年份的一个月内,那么您可以从范围查询中获得不错的性能。例如,给定所有值>=2014-01-01和<2014-02-01.这两个点可以映射回数据库中的数字表示。如果字段有索引,则范围查询可以使用该索引。

但是,如果您要查找的值只是一个月份,那么您提供的任何查询都需要数据库从表中的每个值中提取该月份。这也被称为"表扫描",再多的索引也无济于事。

可以有效使用索引的查询被称为可搜索查询。但是,您尝试的查询是不可搜索的,因为它必须计算表中的每个值。

我不知道你在CRM中对对象及其存储有多大的控制权,但我会告诉你,我通常建议人们直接查询SQL Server:

  • 将月份作为单个整数存储在单独的列中。有时,这可以是基于原始日期时间计算的列,这样您就不必直接输入它。

  • 创建包含此列的索引。

  • 在按月查询时使用此列,以便查询是可查询的。

这是一个猜测,确实应该是一个注释,但它的代码太多,无法很好地格式化注释。如果没有帮助,我会删除答案。

尝试将model.SelectedMonth移动到变量,而不是将其放在Where子句中

var selectedMonth = model.SelectedMonth;
if(selectedMonth != null)
{
    contribs = contribs.Where(x => x.Date.Value.Month == selectedMonth);
}

你也可以对CurrentPage做同样的事情:

int currentPage = model.CurrentPage;
model.Contribs = contribs
    .Skip(NBRESULTSPERPAGE*(currentPage - 1))
    .Take(NBRESULTSPERPAGE)
    .ToList();

与非相关对象的属性相比,许多查询提供程序对变量的处理效果更好。

model.SelectedMonth的类型是什么?

根据您的代码逻辑,它是可以为null的,而且看起来它可能是一个结构,所以这可行吗?

if (model.SelectedMonth.HasValue)
{
    contribs = contribs.Where(x => x.Date.Value.Month == model.SelectedMonth.Value);
}

您可能需要在contrib实体上创建一个Month OptionSet属性,该属性通过创建/更新日期属性实体时的插件填充。然后,您可以按特定月份进行搜索,而不是搜索Date字段,而是搜索int字段。这也将使在高级查找中搜索特定月份变得容易。

Linq to CRM提供商不是Linq的成熟版本。它通常不支持对where语句中的属性进行任何类型的操作,因为它必须转换为QueryExpressions支持的任何类型。