views:

126

answers:

4

I have the classic 3 table - entity, tag and entitytag - database structure.

In order to find all entities tagged with certain tags I am using the following Linqtosql code:

string[] myTags = {"tag1","tag2"};

var query = from m in entity
      where m.entitytag.Where(c => myTags.Contains(c.tag.TagName)).Count() == myTags.Count()
      select m;

However, when entities have duplicate tags(there is a valid reason for this in my real app) the query returns entities that do not match all tags.

eg in the above code sample, if an entity was tagged twice with 'tag1' and not 'tag2' it would return in the results despite not matching both tags.

I cant figure out how to exclude these entities from the results?

Or is there a completely different approach I should be taking?

A: 

How about changing it to

where m.entitytag.Distinct().Where(c => ...

that would remove the duplicate entitytags from your entity objects sub collection, and allow your count to work properly

Eoin Campbell
I have tried that but it still returns the duplicate entries.
geoff
Adding Select(et => et.tag.TagName) before Distinct makes this work. See my answer to this question...
geoff
+1  A: 

Try this query instead:

                    string[] myTags = { "tag1", "tag2" };
                    var query = from m in entity
                                where myTags.All(tag => m.entitytag.Contains(tag))
                                select m;
                    query.Dump();

The All extension method is what will ensure that each tag satisifies the contains criteria.

There is also an Any extension method for cases where you want just one criteria met.

Hope it helps.

Kavan

Kavan Shaban
This is not valid. the 'tag' in your where clause is of type string and not entitytag.
geoff
A: 

As suggested by Eoin, Distinct() needs to be used but it doesn't work against entire entitytag sets. Using another Select statement to only compare against the actual tag is the trick here.

    string[] myTags = {"tag1","tag2"};

    var query = from m in entity
    where m.entitytag.Select(et => et.tag.TagName).Distinct().Where(c => myTags.Contains(c)).Count() == myTags.Count()
    select m;

Unfortunately, the downside is that this hurts performance somewhat.

geoff
A: 

Try

string[] myTags = { "tag1", "tag2" };

var query = from e in entity
            where !myTags.Except(from e.tag select e.tag.TagName).Any()
            select e;

The idea is to remove the entity's tags from a copy of myTags. Any elements left after that correspond to tags that are missing from the entity.

I don't know how this performs, though.

kuhlmancer
You are missing the entitytag table
geoff