情况如下:
我正在寻找一个有点大的实体的基本搜索。现在,结果的数量是可管理的,但我预计在使用一两年后会有大量数据,因此这里的性能非常重要。
我正在浏览的对象具有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();
到目前为止,我得到的是“无效”,其中'条件。实体成员正在调用无效的属性或方法。“我想只是调用ToList()但它看起来效率不高,实体也很大。我正在寻找一种干净的方法来完成这项工作。
答案 0 :(得分:1)
你说:
我正在浏览的对象具有DateTime值,我需要能够输出同月的所有对象,无论年份如何
...
我预计在使用一两年后会有大量数据,因此这里的表现非常重要。
就在那里,你有一个问题。我知道您正在使用LINQ to CRM,但无论您使用何种技术,这个问题实际上都会出现。
根本问题是日期和时间存储在单个字段中。年,月,日,小时,分钟,秒和小数秒都被打包成一个整数,表示自某个时间以来的单位数。对于.NET中的DateTime
,这是自1/1/0001以来 ticks 的数量。如果该值存储在SQL DateTime2
字段中,则它是相同的。其他数据类型具有不同的开始日期(时期)和不同的精度。但在所有情况下,内部只有一个数字。
如果您正在搜索某个特定年份的值,那么您可以从范围查询中获得不错的效果。例如,给出所有值> = 2014-01-01和< 2014年2月1日。这两个点可以映射回数据库中的数字表示。如果该字段具有索引,则范围查询可以使用该索引。
但是,如果您要查找的值只是月,那么您提供的任何查询都需要数据库从表中的每个值中提取该月份。这也称为“表扫描”,没有任何索引可以帮助。
可以有效使用索引的查询称为sargable查询。但是,您尝试的查询是不可搜索的,因为它必须评估表中的每个值。
我不知道你对CRM中的对象及其存储有多少控制权,但我会告诉你我通常建议人们直接查询SQL Server:
将月份作为单个整数存储在单独的列中。有时,这可以是基于原始日期时间的计算列,这样您就不必直接输入它。
创建包含此列的索引。
按月查询时使用此列,以便查询可以进行查询。
答案 1 :(得分:0)
这是一个猜测,实际上应该是一个评论,但是在评论中格式化的代码太多了。如果它没有用,我将删除答案。
尝试将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();
许多查询提供程序使用变量比使用非相关对象的属性更好。
答案 2 :(得分:0)
model.SelectedMonth
的类型是什么?
根据你的代码逻辑,它是可以为空的,看起来它可能是一个结构,所以这有用吗?
if (model.SelectedMonth.HasValue)
{
contribs = contribs.Where(x => x.Date.Value.Month == model.SelectedMonth.Value);
}
答案 3 :(得分:0)
您可能需要在contrib Entity上创建Month OptionSet属性,该属性通过创建/更新日期属性的实体上的插件填充。然后你可以搜索一个特定的月份,而不是搜索Date字段,它搜索一个int字段。这样也可以轻松地在高级查找中搜索特定月份。
Linq to CRM Provider并不是Linq的完整版本。它通常不支持where语句中属性的任何类型的操作,因为它必须转换为QueryExpressions支持的任何操作。