Если вы явно хотите использовать библиотеку динамических запросов LINQ, тогда мой ответ не будет таким, как вы хотите, но если вы хотите получить желаемое поведение и вы счастливы использовать обычный LINQ, тогда я думаю, что могу помочь.
По сути, я создал класс EntryGrouper
, который обрабатывает логику группировки по выбранным значениям в раскрывающихся списках, и я предположил, что переменные section
, page
& module
содержат эти значения. Я также предположил, что ObjectContext.OmniturePageModules
является перечислимым типом Entry
.
Таким образом, ваш запрос LINQ теперь становится этими двумя:
var entries = (from entry in ObjectContext.OmniturePageModules
where entry.StartOfWeek >= startDate
&& entry.StartOfWeek <= endDate
&& (section == "Total" || section == "All" || entry.Section == section)
&& (page == "Total" || page == "All" || entry.Page == page)
&& (module == "Total" || module == "All" || entry.Module == module)
select entry).ToArray(); // Force query execution
var grouping = from entry in entries
let grouper = new EntryGrouper(entry, section, page, module)
group entry by grouper into entryGroup
select new
{
SeriesName = entryGroup.Key.SeriesName,
Week = entryGroup.Key.StartOfWeek,
Clicks = entryGroup.Sum(p => p.Clicks),
};
Первый запрос используется для принудительного запроса простого выбора в базе данных и возврата только тех записей, которые вы хотите сгруппировать. Как правило, group by
запросы вызывают базу данных несколько раз, поэтому запросы таким образом обычно выполняются намного быстрее.
Второй запрос группирует результаты первого запроса, создавая экземпляры класса EntryGrouper
в качестве ключа группировки.
Я включил свойство SeriesName
в класс EntryGrouper
, чтобы вся логика группировки была четко определена в одном месте.
Теперь класс EntryGrouper
достаточно велик, так как для работы группировки необходимо иметь свойства для StartOfWeek
, Section
, Page
& Module
и содержать перегрузки Equals
& GetHashCode
и реализуйте интерфейс IEquatable<Entry>
.
Вот оно:
public class EntryGrouper : IEquatable<Entry>
{
private Entry _entry;
private string _section;
private string _page;
private string _module;
public EntryGrouper(Entry entry, string section, string page, string module)
{
_entry = entry;
_section = section;
_page = page;
_module = module;
}
public string SeriesName
{
get
{
return String.Format("{0}:{1}:{2}", this.Section, this.Page, this.Module);
}
}
public DateTime StartOfWeek
{
get
{
return _entry.StartOfWeek;
}
}
public string Section
{
get
{
if (_section == "Total" || _section == "All")
return _section;
return _entry.Section;
}
}
public string Page
{
get
{
if (_page == "Total" || _page == "All")
return _page;
return _entry.Page;
}
}
public string Module
{
get
{
if (_module == "Total" || _module == "All")
return _module;
return _entry.Module;
}
}
public override bool Equals(object other)
{
if (other is Entry)
return this.Equals((Entry)other);
return false;
}
public bool Equals(Entry other)
{
if (other == null)
return false;
if (!EqualityComparer<DateTime>.Default.Equals(this.StartOfWeek, other.StartOfWeek))
return false;
if (!EqualityComparer<string>.Default.Equals(this.Section, other.Section))
return false;
if (!EqualityComparer<string>.Default.Equals(this.Page, other.Page))
return false;
if (!EqualityComparer<string>.Default.Equals(this.Module, other.Module))
return false;
return true;
}
public override int GetHashCode()
{
var hash = 0;
hash ^= EqualityComparer<DateTime>.Default.GetHashCode(this.StartOfWeek);
hash ^= EqualityComparer<string>.Default.GetHashCode(this.Section);
hash ^= EqualityComparer<string>.Default.GetHashCode(this.Page);
hash ^= EqualityComparer<string>.Default.GetHashCode(this.Module);
return hash;
}
public override string ToString()
{
var template = "{{ StartOfWeek = {0}, Section = {1}, Page = {2}, Module = {3} }}";
return String.Format(template, this.StartOfWeek, this.Section, this.Page, this.Module);
}
}
Логика группировки этого класса выглядит просто так:
if (_page == "Total" || _page == "All")
return _page;
return _entry.Page;
Если я неправильно понял, как из выпадающих значений включается и выключается группировка, вам просто нужно изменить эти методы, но суть этого кода в том, что при группировке он должен возвращать групповое значение на основе значения в запись и в противном случае она должна возвращать общее значение для всех записей. Если значение является общим для всех записей, то оно логически создает только одну группу, которая является такой же, как не группировка вообще.
Если у вас есть больше выпадающих списков, по которым вы группируете, вам нужно добавить больше свойств в класс EntryGrouper
. Не забудьте также добавить эти новые свойства в методы Equals
& GetHashCode
.
Следовательно, эта логика представляет собой динамическую группировку, которую вы хотели. Пожалуйста, дайте мне знать, если я помог или вам нужно больше подробностей.
Наслаждайтесь!