-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Query help: All Links with all Tags
PostPosted: Mon Sep 29, 2008 8:35 pm 
Newbie

Joined: Sat Jun 09, 2007 7:41 am
Posts: 4
Location: Melbourne
Hibernate version: 2.0GA

How can I construct the following query using NH?

Get me all reports (type of link) that have all of the these tags: (expressed as all Links where there's not a Tag in the given list that is not a LinkTag for the Link).
Code:
select l.Id, l.Text
from Link l
where _discriminator = 'ReportLink'
and not exists
   (select * from Tag t
    where not exists
      (select * from LinkTag lt
       where lt.LinkFK = l.Id
       and lt.TagFK = t.Id)
    and t.Name in ('tag1', 'tag3'))

It's the classic all customers that have ordered all of these products, but in NH the LinkTag table isn't a first-class citizen, being there (at present) only to facilitate the many-to-many.

I'd prefer to use NHibernate.Linq before the Criteria API, before HQL, before SQL.

The 'obvious' Linq query did nothing, which is fine as I know it's experimental:
Code:
    public IEnumerable<Report> ReportsHavingAllOfTags(IEnumerable<string> tags)
    {
         return Query
                .Where(report => report.Tags.All(tag => tags.Contains(tag.Name)))
                .OrderBy(report => report.Text);
    }


Is the answer to change the many-to-many into one-to-many from each end and make the resolving table an entity in it's own right and use Subqueries.NotExists?

Does anyone know a clever solution?


Persistent types and mapping attributes:
Link class (abbreviated for clarity):
Code:
    [Class(Table = "Link", DiscriminatorValueObject = LinkDiscriminators.Link)]
    [Discriminator(TypeType = typeof(string), Column = "_discriminator", Length = 50)]
    public abstract partial class Link
    {
        protected ISet<Tag> tags = new HashedSet<Tag>();

        [Id(1, Name = "Id", TypeType = typeof(int), UnsavedValueObject = 0)]
        [Generator(2, Class = "native")]
        public virtual int Id { get; set; }

        /// <summary>
        /// The text describing the link
        /// </summary>
        [Property(Column = "[Text]", Length = Constraints.DescriptionLength)]
        public virtual string Text { get; set; }

        /// <summary>
        /// A set of tags on this link.
        /// </summary>
        [Set(10, Table = "LinkTag", Inverse = false, Lazy = true, Access = "nosetter.camelcase", Cascade = CascadeStyle.All)]
        [Key(20, Column = "LinkFK", ForeignKey = "FK_LinkTag_Link")]
        [ManyToMany(30, ClassType = typeof(Tag), ForeignKey = "FK_LinkTag_Tag"), Column(31, Name = "TagFK", NotNull = true)]
        public virtual IEnumerable<Tag> Tags
        {
            get { return tags; }
        }
    }

Report class (abbreviated for clarity):
Code:
    [Subclass(ExtendsType = typeof(Link), DiscriminatorValueObject = LinkDiscriminators.ReportLink)]
    public partial class Report : Link
    {
    }

Tag class:
Code:
    [Class(Table = "Tag")]
    public class Tag
    {
        [Id(1, Name = "Id", TypeType = typeof(int), UnsavedValueObject = 0)]
        [Generator(2, Class = "native")]
        public virtual int Id { get; set; }

        [Property(Length = Constraints.NameLength)]
        public virtual string Name { get; set; }
    }


Top
 Profile  
 
 Post subject: [SOLVED]
PostPosted: Tue Sep 30, 2008 7:01 pm 
Newbie

Joined: Sat Jun 09, 2007 7:41 am
Posts: 4
Location: Melbourne
Not pretty, but it does the job...
Code:
var queryText =
      string.Format(
            "not exists (select * from Tag t where not exists " +
            "(select * from LinkTag lt where lt.LinkFK = this_.Id and lt.TagFK = t.Id) and t.Name in " +
            "({0}))",
            string.Join(", ", tags.Select(s => "?").ToArray())
            );

ICriteria q = repository.CriteriaQuery<Report>()
      .Add(Expression.Sql(queryText, tags.ToArray(), tags.Select(s => NHibernateUtil.String).ToArray()));


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.