Linq query against a collection property with a collection parameter

Go To StackoverFlow.com

2

I have a method which takes an array of strings as parameter and queries against a collection property which is also a collection of strings. If that property has one of the values inside the string array passed as parameter, it should be returned.

Here is my code:

public IEnumerable<BlogPost> GetAll(string[] tags, 
    bool includeUnapprovedEntries = false) {

    foreach (var tag in tags) {
        foreach (var blogPost in GetAll(includeUnapprovedEntries).
            ToList().Where(x => x.Tags.Any(t => t == tag))) {
            yield return blogPost;
        }
    }
}

Note:

Here is the complete code:

https://github.com/tugberkugurlu/MvcBloggy/blob/master/src/MvcBloggy.Data/DataAccess/SqlServer/BlogPostRepository.cs

This does the job but it just doesn't seem right. I could have made this better with some extension methods but couldn't figure out what would do the trick and make this implementation right.

Any idea?

2012-04-04 07:06
by tugberk


4

How about this:

public IEnumerable<BlogPost> GetAll(string[] tags,
    bool includeUnapprovedEntries = false) {

    return GetAll(includeUnapprovedEntries)
        .Where(x => x.Tags.Any(t => tags.Contains(t));
}

You may want to call ToList() to materialize the result. Note that this will (hopefully!) result in an IN query in SQL; if you have a large number of tags, I wouldn't be surprised if that failed. (I don't know how the Entity Framework handles that situation.) I believe it should be okay with smaller numbers of tags though.

Note that whether or not this is supported may depend on the version of the entity framework you're using; I seem to remember that some transformations like this (using Contains on a "local" collection) to translate to IN in SQL) have improved over time. Make sure you develop against the same version you'll be deploying against :)

2012-04-04 07:09
by Jon Skeet
Ah, I feel so bad right now. I guess I shouldn't code after 1 AM anymore. Thanks - tugberk 2012-04-04 07:13
@tugberk: Have you checked that it actually works though? Don't assume it will until you've tried it :) I'm reasonably good at predicting how LINQ to Objects will behave, but I've very little experience (essentially nil) with the Entity Framework - Jon Skeet 2012-04-04 07:14
Also, I should mention that this query really doesn't go to SQL Server. I created a tag collection over semicolon-separated string (as it is here: https://github.com/tugberkugurlu/MvcBloggy/blob/master/src/MvcBloggy.Data/DataAccess/SqlServer/Model/BlogPost.cs). So, it gets the whole data with GetAll (yep, it is a really bad approach but I couldn't figure out the other way) and does the query against that. So, it is mostly Linq to Objetcs - tugberk 2012-04-04 07:19
@tugberk: Ah, in that case I'd potentially consider converting tags to a HashSet<string> first, at least if there are going to be quite a few of them to match against. That will make each match simpler - Jon Skeet 2012-04-04 07:21
I see. I wonder if HashSet is something that allows me to query against SQL Server in this situation since the data type inside my SQL table is just NVARCHAR. Also, I am sure that my current implementation will result a bottleneck in my application as the data grows because I am getting the whole data at once and query against those inside the memory but it is a different topic than this question's - tugberk 2012-04-04 07:25
@tugberk: No, if you do want to issue the query against SQL Server, just use the array. A HashSet would just make the in-memory processing simpler. As you say, sorting out your design so that you can perform the query in SQL is probably a different matter : - Jon Skeet 2012-04-04 07:28
Ah, I see. Thanks! I will try to figure out if storing tags inside a different table which has FK to BlogPosts table would be better. That way, I may generate an IN query with your above approach - tugberk 2012-04-04 07:31
@JonSkeet Jon Skeet doesn't get compiler errors, Visual Studio just apologises and alters the framework accordingl - mattytommo 2012-04-04 10:25
Ads