Accepted answer

I believe you can find notes that have the relevant tags in a single LINQ expression:

IQueryable<Note> query = ... // top part of query

query = query.Where(note => searchTags.All(st =>
    note.Tags.Any(notetag => notetag.Id == st.Id)));

Unfortunately there is no “fluent syntax” equivalent for All and Any, so the best you can do there is

query = from note in query
        where searchTags.All(st =>
            note.Tags.Any(notetag => notetag.Id == st.Id))
        select note;

which is not that much better either.


For starters see my comment; I suspect the query is wrong anyway! I would simplifiy it, by simply enforcing separately that each tag exists:

IQueryable<Note> query = ... // top part of query
foreach(var tagId in searchTagIds) {
    var tmpId = tagId; // modified closures...
    query = query.Where(note => note.Tags.Any(t => t.Id == tmpId));

This should have the net effect of enforcing all the tags specified are present and accounted for.


Timwi's solution works in most dialects of LINQ, but not in Linq to Entities. I did find a single-statement LINQ query that works, courtesy of ReSharper. Basically, I wrote a foreach block to do the search, and ReSharper offered to convert the block to a LINQ statement--I had no idea it could do this.

I let ReSharper perform the conversion, and here is what it gave me:

return searchTags.Aggregate<Tag, IQueryable<Note>>(DataStore.ObjectContext.Notes, (current, tag) => current.Where(n => n.Tags.Any(t => t.Id == tag.Id)).OrderBy(n => n.Title));

I read my Notes collection from a database, using Entity Framework 4. DataStore is the custom class I use to manage my EF4 connection; it holds the EF4 ObjectContext as a property.

Related Articles