如果您明确地想要使用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),
               };
  
   第一个查询用于强制对数据库执行简单的select查询,并仅返回要分组的记录。一般来说
   
    group by
   
   查询多次调用数据库,因此以这种方式进行查询通常要快得多。
  
  
   第二个查询通过创建
   
    入口石斑鱼
   
   类作为分组键。
  
  
   我已经包括了
   
    SeriesName
   
   中的属性
   
    入口石斑鱼
   
   类,以便在一个位置整齐地定义所有分组逻辑。
  
  
   现在,
   
    入口石斑鱼
   
   类非常大,因为为了允许分组工作,它需要具有
   
    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;
  
   如果我误解了下拉值是如何打开和关闭分组的,那么您应该只需要更改这些方法,但这段代码的关键在于,当分组打开时,它应该根据条目中的值返回一个组值,否则它应该为所有条目返回一个公共值。如果该值对于所有条目都是通用的,那么逻辑上它只创建一个与完全不分组相同的组。
  
  
   如果要分组的下拉列表更多,则需要向
   
    入口石斑鱼
   
   班级。不要忘记将这些新属性添加到
   
    等于
   
   和;
   
    方法
   
   方法也是如此。
  
  
   因此,这个逻辑表示您想要的动态分组。请告诉我我是否帮助过你,或者你是否需要更多的细节。
  
  
   享受!