score:3

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.

score:0

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.

score:0

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