У меня есть, казалось бы, простое требование, но я не могу понять, как записать его в качестве запроса, который имеет только один обратный рейс на сервер.Агрегация запросов Linq по месяцам активна
В принципе у меня есть простая таблица
CREATE TABLE Item
(
id int not null identity(1,1),
create datetime not null,
close datetime --null means not closed yet
);
и то, что я хочу сделать, это в некотором диапазоне времени (скажем, 1/1/2010 до 6/1/2010), за каждый месяц я нужен количество элементов, которые были активны в этом месяце. элемент активен, если он был создан либо во время, либо до этого месяца и либо не закрыт (т. е. закрыт недействителен), либо закрыт после этого месяца. Поэтому я перевел это в выражение Linq, используя вспомогательный метод:
//just returns the first day of every month inbetween min and max (inclusive)
private IEnumerable<DateTime> EnumerateMonths(DateTime Min, DateTime Max)
{
var curr = new DateTime(Min.Year, Min.Month, 1);
var Stop = new DateTime(Max.Year, Max.Month, 1).AddMonths(Max.Day == 1 ? 0 : 1);
while(curr < Stop)
{
yield return curr;
curr = curr.AddMonths(1);
}
}
public List<DataPoint> GetBacklogByMonth(DateTime min, DateTime max)
{
return EnumerateMonths(min, max)
.Select(m => new DataPoint
{
Date = m,
Count = DB.Items.Where(s => s.Create <= m.AddMonths(1) && (!s.Close.HasValue || s.Close.Value >= m.AddMonths(1)))
.Count()
}
).ToList();
}
, который прекрасно работает, за исключением каждого Count
представляет собой отдельный запрос для его супер медленно (туда и обратно за каждый месяц), так что мой вопрос, как мог Я реструктурирую этот запрос, чтобы сделать это в одном раунде на сервер.
Первоначально я думал о том, чтобы делать какую-то группу по сумме по месяцам, но поскольку каждый элемент может быть «активным» в разные месяцы, я не думаю, что это сработает.
Любые предложения?
это должно работать, но возможно, что он может вывести несколько тысяч строк, это может быть слишком много сетевого трафика. плохо попробуйте и посмотрите, приемлемо ли это. – luke
Если строки большие, вы можете 'Select()' просто столбцы «Создать» и «Закрыть». Другой альтернативой, если вы используете MS SQL Sever, является создание функции CLR, которая будет выполнять работу на стороне сервера. Затем вы можете добавить эту функцию в качестве метода в вашем сопоставлении LINQ-to-SQL. http://msdn.microsoft.com/en-us/library/ms189876.aspx – Jay