简体   繁体   中英

IQueryable for where with multi list compare

I have a basic IQueryable,

private static IQueryable<TestObject> GetFilteredQuery(Guid componentId, Guid productId)
    {
      IQueryable<TestObject> query = from t in ModelQuery.Query<TestObject>()
                                     where t.ComponentId == componentId && t.ProductId == productId
                                     select t;
      return query;
    }

This is trivial if I have to compare single componentId and productId.

My problem is how can I handle when I have a list of value pairs,

Guid[] componentIds, Guid[] productIds

where, its kind of a keyValue pair.

something like,

 private static IQueryable<TestObject> GetFilteredQuery(Guid[] componentIds, Guid[] productIds)
    {
      IQueryable<TestObject> query = from t in ModelQuery.Query<TestObject>()
                                     where (t.ComponentId must be present in componentIds[] && t.ProductId must be present in productIds)
                                     select t;
      return query;
    }

Use Contains :

 private static IQueryable<TestObject> GetFilteredQuery(Guid[] componentIds, Guid[] productIds)
    {
      IQueryable<TestObject> query = 
         from t in ModelQuery.Query<TestObject>()
         where (componentIds.Contains(t.ComponentId) 
                && productIds.Contains(t.ProductId))
         select t;
      return query;
    }

Edit

AFAIK there is no way Linq2Sql is going to map a sequence of Guid tuples to native Sql (you would likely need an @Table parameter for this)

So here's one approach, viz to run a query the same contains as above, but using OR on the 2 filter lists. Sql will hopefully be able to filter a significant amount of data out at the database level.

The results ( candidates ) then need to be materialized, and then filtered in memory against the component and product pairs. I've done this by zipping the 2 guid arrays together (assuming similar length - possibly you want to remodel the arrays as an array of Pairs to express the intention more explicitly?)

private static IQueryable<TestObject> GetFilteredQuery(Guid[] componentIds, 
                                                       Guid[] productIds)
{
    var candidates = ModelQuery
         .Query<TestObject>()
         .Where(componentIds.Contains(
                         t.ComponentId) || productIds.Contains(t.ProductId))
         .ToList();// Need to materialize

    var guidPairs = componentIds.Zip(productIds, 
          (c, p) => new {ComponentId = c, ProductId = p});

    return candidates
      .Join(guidPairs, 
            c => new {ComponentId = c.ComponentId, ProductId = c.ProductId}, 
            gp => gp, 
            (c, gp) => c)
      .AsQueryable();
}

Note that the resultant queryable isn't really suitable for further composition, given that it has already been materialized. Also, if you can do additional filtering before hitting this, it would be beneficial. And I'm afraid I haven't actually tested this.

使用Contains

where componentIds.Contains(t.ComponentId) && productIds.Contains(t.ProductId)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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