【问题标题】:Do you know another way to do this "massive" linq filtering?你知道另一种方法来做这个“大规模”linq过滤吗?
【发布时间】:2012-03-08 01:35:12
【问题描述】:

这是我的代码:

// I STORE THE USER SELECTED VALUES
IList<string> SelectedCity = (from CheckBox loc in panelCity.Controls.OfType<CheckBox>()
                              where loc.Checked
                              select loc.InputAttributes["value"]).ToList();

IList<string> SelectedCategories = (from CheckBox strut in panelCategories.Controls.OfType<CheckBox>()
                                    where strut.Checked
                                    select strut.InputAttributes["value"]).ToList();

// I GET ALL RECORDS
IList<Hotel> Hotels = (from Hotel hotel in new Hotels()
                       orderby hotel.Titolo ascending
                       select hotel).ToList();

// I FILTER THEM
if (SelectedCity.Count > 0)
    Hotels = Hotels.Where(o => o.City != null && SelectedCity.Contains(o.City.UniqueID)).ToList();

if (SelectedCategories.Count > 0)
    Hotels = Hotels.Where(o => o.Category != null && SelectedCategories.Contains(o.Category.UniqueID)).ToList();

所以,如您所见,我做了一些查询,存储从用户中选择的值。比,对于每个酒店行,我循环城市和类别的数组。

这个,有很多行,非常昂贵。

您知道其他优化研究的方法吗?

【问题讨论】:

  • 您是否尝试过仅在最终结果中使用ToList()?这样做时不要忘记更改变量的类型。

标签: c# .net linq filtering


【解决方案1】:

将您的城市和类别放入HashSet&lt;string&gt; 以节省查找时间:

HashSet<string> selectedCities = new HashSet<string>(SelectedCity); 
HashSet<string> selectedCategories = new HashSet<string>(SelectedCategories); 

在你的查询完全组装之前你不需要使用ToList(),否则你会遍历多次:

var hotels = from Hotel hotel in new Hotels()
             select hotel;

if (SelectedCity.Any())
    hotels = hotels.Where(o => o.City != null && selectedCities.Contains(o.City.UniqueID));

if (SelectedCategories.Any())
    hotels = hotels.Where(o => o.Category != null && selectedCategories.Contains(o.Category.UniqueID));

最后,一旦您过滤掉所有不想要的酒店,就可以进行排序,这样您就可以减少排序的项目:

hotels = hotels.OrderBy(h=> h.Titolo);

最后一步实现结果:

Hotels = hotels.ToList();

【讨论】:

  • 那么您是说将列表存储到哈希集中?
  • 是的 - 鉴于您正在寻找城市和类别,因此不应有任何重复,因此您可以使用哈希集进行 O(1) 查找时间。
  • @markzzz:澄清一下:酒店是来自数据库还是内存中的集合?
  • Hotels() 获取元素集合,取自 DB :) 构造函数调用存储过程...
  • 理想情况下,您希望在数据库中进行过滤,否则速度会慢得多 - 确保 Hotels 返回 IQueryable&lt;Hotel&gt; 而不是内存中的集合,否则速度会慢几个数量级跨度>
【解决方案2】:

至少,您可以将 Where 子句组合到上述 Linq 语句中:

IList Hotels =(来自新酒店中的酒店酒店() 其中 SelectedCity.Count > 0 && hotel.City != null && SelectedCity.Contains(hotel.City.UniqueID) 其中 SelectedCategories.Count > 0 && hotel.Category != null && SelectedCategories.Contains(hotel.Category.UniqueID) orderby hotel.Titolo 上升 选择酒店).ToList();

【讨论】:

    【解决方案3】:

    仅从这里猜测,但最热门的似乎是获取所有酒店,因为您只需要城市或类别来进行后续查询。

    如果您只是选择所需的输入来获取匹配的 Id,那么选择匹配的酒店可能会有所改善。

    【讨论】:

      【解决方案4】:

      将所有酒店加载到内存中进行搜索是非常无效的;但是,如果您不加载所有酒店,您将无法在集合中调用Contains()。相反,您可以使用 Joseph Albahari site 中的 PredicateBuilder 来构建一个谓词,该谓词可用于仅获取符合条件的酒店。

      var inSelectedCities = PredicateBuilder.True<Hotel>();
      foreach(var city in SelectedCity)
      {
          string temp = city;
          inSelectedCities = inSelectedCities.Or(h => h.City.UniqueId == temp);
      }
      var inSelectedCategories = PredicateBuilder.True<Hotel>();
      foreach(var category in SelectedCategories)
      {
          string temp = category;
          inSelectedCategories = inSelectedCategories.Or(h => h.Category.UniqueId == temp)
      }
      var hotels = Hotels
                      .Where(inSelectedCities.Or(inSelectedCategories))
                      .ToList();
      

      【讨论】:

        【解决方案5】:

        性能问题显然出在命中数据库的 Hotels 构造函数中。如果该构造函数使用 LinqToSql 或 LinqToEntities,您应该将 Expression&lt;Func&lt;Hotel, bool&gt;&gt; 传递到那里以从 Queryable.Where 调用并在数据库端完成一些过滤。

        如果该构造函数不使用 Linq,您将不得不以另一种方式传达过滤...也许通过传入条件列表。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-08-30
          • 2012-03-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多