4

For some reason i can't get this query right, and i can't understand why...

I have an object called 'Blog' that has an Id, and a list of 'Tag's.
Each 'Tag' has an id and a 'Name' property.

Since this is a many to many relationship, I have another table called 'blog_tags' connecting them.

The mappings look like this :

public class BlogsMapping : ClassMap<Blog>
{
    Table("blogs");
    Id(x => x.Id).GeneratedBy.Identity();
    Map(x => x.Content);
    HasManyToMany(x => x.Tags)
        .Table("Blog_Tags")
        .ParentKeyColumn("BlogId")
        .ChildKeyColumn("TagId")
        .Not.LazyLoad()
        .Cascade.All();
}

public class TagsMapping : ClassMap<Tag>
{
    Table("tags");
    Id(x => x.Id).GeneratedBy.Identity();
    Map(x => x.Name);
}

I would like to retrieve a list of blogs that have all of the following (some list) of tags.

I would like to do something like this :

public IList<Blog> Filter(string[] tags)
{
    var blogs = _session.QueryOver<Blog>()
        .Where(x => x.Tags.ContainsAll(tags));
    return blogs.ToList();
}

I tried a couple of different ways, but always run into different and weird errors, so i was hoping that someone could just point me in the right direction...

gillyb
  • 8,760
  • 8
  • 53
  • 80

1 Answers1

2

You should be able to do it with something like this:

string[] tagNames = new string[2]{ "Admins", "Users" };

using (NHibernate.ISession session = SessionFactory.GetCurrentSession())
{
    IList<Blog> blogsFound = session.QueryOver<Blog>()
                                    .Right.JoinQueryOver<Tags>(x => x.Tags)
                                    .WhereRestrictionOn(x => x.Name).IsIn(tagNames)
                                    .List<Blog>();

}

Edit

The below is what I was talking about with the subquery. It's not really a subquery but you have to 1st get a list of values (tag names) that you don't want to include in your results.

string[] tagNames = new string[2]{ "Admins", "Users" };
IList<string> otherTags = 
    session.QueryOver<Tag>()
           .WhereRestrictionOn(x => x.Name).Not.IsIn(tagNames)
           .Select(x => x.Name)
           .List<string>();

string[] otherTagNames = new string[otherTags.Count];
otherGroups.CopyTo(otherTagNames, 0);

IList<Blog> blogsFound = 
    session.QueryOver<Blog>()
           .Right.JoinQueryOver<Tag>(x => x.Tags)
           .WhereRestrictionOn(x => x.Name).IsIn(tagNames)
           .WhereRestrictionOn(x => x.Name).Not.IsIn(otherTagNames)
           .List<Blog>();
Cole W
  • 15,123
  • 6
  • 51
  • 85
  • I didn't try this yet, but it seems like this will check that all the Blog's tags are in the tagNames array, and what i want is the other way around - I need to check that all the strings in tagNames are in the Blog Tags list, and not necessarily match exact. I'll try it soon, and let you know... Thanks! – gillyb Jan 15 '12 at 13:37
  • This doesn't really work...
    It checks to see if the blog has a tag in the tags list, but doesn't check if it has all of them...
    – gillyb Jan 28 '12 at 15:30
  • @gillyb You'll have to do a subquery to do what you are wanting. You would subquery all the possible values for possible tag names and do a NotIn to do this as well as the IsIn that you already have. – Cole W Jan 28 '12 at 16:24
  • I still don't think that what you posted works the way i want it to... Can i email you about this ? It'll be easier for me to explain... – gillyb Feb 16 '12 at 20:44
  • ...and if you don't answer, for what it's worth, Thanks a lot for your help!!! I really appreciate it! :) – gillyb Feb 16 '12 at 20:45
  • Do you know how to do this in SQL? If so post it in your question. – Cole W Feb 16 '12 at 21:13