У меня есть приложение, которое позволяет пользователям вводить время, которое они проводят за работой, и я пытаюсь создать для этого хорошую отчетность, которая использует LINQ to Entities. Поскольку у каждого TrackedTime
есть TargetDate
которая является просто частью «Date» DateTime
, относительно просто сгруппировать время по пользователю и дате (я упускаю предложения «where» для простоты):
var userTimes = from t in context.TrackedTimes
group t by new {t.User.UserName, t.TargetDate} into ut
select new
{
UserName = ut.Key.UserName,
TargetDate = ut.Key.TargetDate,
Minutes = ut.Sum(t => t.Minutes)
};
Благодаря свойству DateTime.Month
группировка по пользователю и месяцу лишь немного сложнее:
var userTimes = from t in context.TrackedTimes
group t by new {t.User.UserName, t.TargetDate.Month} into ut
select new
{
UserName = ut.Key.UserName,
MonthNumber = ut.Key.Month,
Minutes = ut.Sum(t => t.Minutes)
};
Теперь самое сложное. Есть ли надежный способ группировки по неделям? Я попробовал следующее на основе этого ответа на похожий вопрос LINQ to SQL:
DateTime firstDay = GetFirstDayOfFirstWeekOfYear();
var userTimes = from t in context.TrackedTimes
group t by new {t.User.UserName, WeekNumber = (t.TargetDate - firstDay).Days / 7} into ut
select new
{
UserName = ut.Key.UserName,
WeekNumber = ut.Key.WeekNumber,
Minutes = ut.Sum(t => t.Minutes)
};
Но LINQ to Entities не поддерживает арифметические операции над объектами DateTime, поэтому не знает, как это сделать (t.TargetDate - firstDay).Days / 7
.
Я подумал о создании представления в базе данных, которое просто отображает дни и недели, а затем добавляет это представление в мой контекст Entity Framework и присоединяется к нему в моем запросе LINQ, но кажется, что для такой работы требуется много работы. Есть ли хороший обходной путь для арифметического подхода? Что-то, что работает с Linq to Entities, что я могу просто включить в оператор LINQ, не касаясь базы данных? Какой-нибудь способ рассказать Linq Entities, как вычесть одну дату из другой?
Я хотел бы поблагодарить всех за их вдумчивые и творческие ответы. После всего этого, похоже, реальный ответ на этот вопрос - «подождите до .NET 4.0». Я собираюсь отдать награду Нолдорину за самый практичный ответ, который до сих пор использует LINQ, с особым упоминанием Якоба Проффитта за то, что он придумал ответ, который использует Entity Framework без необходимости изменений на стороне базы данных. Были и другие отличные ответы, и если вы смотрите на вопрос впервые, я настоятельно рекомендую прочитать все те, за которые проголосовали, а также их комментарии. Это действительно был превосходный пример силы StackOverflow. Спасибо вам всем!
Вы должны быть в состоянии заставить запрос использовать LINQ to Objects вместо LINQ to Entities для группировки, используя вызов метода расширения AsEnumerable
.
Попробуйте следующее:
DateTime firstDay = GetFirstDayOfFirstWeekOfYear();
var userTimes =
from t in context.TrackedTimes.Where(myPredicateHere).AsEnumerable()
group t by new {t.User.UserName, WeekNumber = (t.TargetDate - firstDay).Days / 7} into ut
select new
{
UserName = ut.Key.UserName,
WeekNumber = ut.Key.WeekNumber,
Minutes = ut.Sum(t => t.Minutes)
};
Это, по крайней мере, означает, что предложение where
выполняется LINQ to Entities, а предложение group
, которое слишком сложно для Entities, обрабатывается LINQ to Objects.
Дайте мне знать, если вам повезет с этим.
Вот еще одно предложение, которое может позволить вам использовать LINQ to Entities для всего этого.
(t.TargetDate.Days - firstDay.Days) / 7
Это просто расширяет операцию, так что выполняется только целочисленное вычитание, а не вычитание DateTime
.
В настоящее время он не проверен, поэтому он может или не может работать ...
Вы можете использовать функции SQL также в LINQ, если вы используете SQLServer:
using System.Data.Objects.SqlClient;
var codes = (from c in _twsEntities.PromoHistory
where (c.UserId == userId)
group c by SqlFunctions.DatePart("wk", c.DateAdded) into g
let MaxDate = g.Max(c => SqlFunctions.DatePart("wk",c.DateAdded))
let Count = g.Count()
orderby MaxDate
select new { g.Key, MaxDate, Count }).ToList();
Этот образец был адаптирован из MVP Zeeshan Hirani в этой теме: MSDN