简体   繁体   English

使用Linq过滤多级where子句

[英]Multiple level where clause filtering with Linq

Say I have some filter criteria passed into my application via an array of CustomerFilter objects where I need to run a query and return the results based on those filters from a Linq to Entities query. 假设我有一些过滤条件通过CustomerFilter对象数组传递到我的应用程序中,我需要运行查询并根据从Linq到Entities查询的过滤器返回结果。

So in this case the customer would be passing me in an array of CustomerFilter objects over the service call. 因此,在这种情况下,客户将通过服务调用将一组CustomerFilter对象传递给我。

Filter Object: 过滤对象:

class CustomerFilter
{
    public string CustomerID;
    public int[] LocationID;
}

Example Data: 示例数据:

CustomerID    LocationID 

1             1

              2

              3

              4 

2             2 

              3 


              4

I can build a query filtering on the outer CustomerID quite easily as below. 我可以很容易地在外部CustomerID上构建查询过滤,如下所示。

Query: 查询:

    public void GetCustomerResults(List<CustomerFilter> accounts)
    {
        List<string> customer = (from a in accounts select a.CustomerID).ToList();

        var locations = ctx.Portal_SurveyLocations
                            .Where(w => customer.Contains(w.CustNum))
                            .OrderBy(o => o.LocationKey);
    }

So I can filter by the outer criteria but I am not sure how to filter by the multiple location IDs for each CustomerID. 所以我可以按外部标准进行筛选,但我不确定如何根据每个CustomerID的多个位置ID进行筛选。 Obviously just putting an OR clause would give incorrect results as it would pull in other CustomerIDs with matching LocationIDs. 显然只是放置一个OR子句会产生不正确的结果,因为它会引入具有匹配LocationID的其他CustomerID。

Any ideas of how to accomplish this multiple level filter given the CustomerFilter object passed in? 在传入CustomerFilter对象的情况下,如何实现此多级过滤器的任何想法?

Slight rework. 轻微返工。 Basically, we use a combination of Any to traverse the sub-collections to achieve the desired result. 基本上,我们使用Any的组合来遍历子集合以实现期望的结果。

var locations = ctx.Portal_SurveyLocations
    .Where(w => accounts.Any(a => a.CustomerID == w.CustNum &&
                                  a.LocationID.Any(l => w.LocationKey == l)))
    .OrderBy(o => o.LocationKey);

For fast lookup (using Contains on a List isn't very fast) you can create a dictionary of hash sets from the filter objects. 对于快速查找(使用List上的Contains不是很快),您可以从过滤器对象创建哈希集的字典。

The dictionary would contain one item for each customer, and the value in that item would be a hash set of the locations. 字典将为每个客户包含一个项目,该项目中的值将是位置的哈希集合。 When using it, first you check if the customer is in the dictionary, then you check if the location is in the hash set for that customer: 使用它时,首先检查客户是否在字典中,然后检查该位置是否在该客户的哈希集中:

public void GetCustomerResults(List<CustomerFilter> accounts) {
  Dictionary<string, HashSet<int>> lookup =
    accounts.ToDictionary(a => a.CustomerID, a => new HashSet<int>(a.LocationID));

    var locations =
      ctx.Portal_SurveyLocations
      .Where(w =>
        lookup.ContainsKey(w.CustNum) &&
        lookup[w.CustNum].Contains(w.LocationKey))
      .OrderBy(o => o.LocationKey);
}

Both the dictionary and the hash set have an O(1) complexity for looking up an item, so the entire operation gets an O(n+m) complexity, where n is the number of filters, and m is the number of items in Portal_SurveyLocations . 字典和散列集都具有查找项目的O(1)复杂度,因此整个操作获得O(n+m)复杂度,其中n是过滤器的数量, m是项目的数量Portal_SurveyLocations

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM