tags:

views:

750

answers:

2

Hello there,

I have this hql query, which works perfect:

            select m 

            from Media m

            join m.Productlines p
            join m.Categories c                
            join m.Spaces sp
            join m.Solutions so

            where m.Uid != 0
            and p.Uid in (:productlines)
            and c.Uid in (13)                
            and sp.Uid in (52)
            and so.Uid in (15,18)

            group by m.Uid

But now it needs to be parameterized/made dynamic, not only the parameters, but also the joins (it is possible to select only from Media, without any joins, and so no *.Uid in will be required in this case).

I dont want to mess around with a StringBuilder instance and build the hql query that way, I would rather like to use the Criteria API, but I cant get a

SELECT m.*
....
GROUP BY m.Uid

query to work with Criteria.

If I add a

Projections.GroupProperty("Uid")

to my query, nhibernate selects

SELECT m.Uid
....
GROUP BY m.Uid

which is of course wrong.

After that, I also need to count the unique rows the query returned, as the result is paged.

So, my other query is quite similiar, but I cant find a Criteria equivalent for

SELECT COUNT(DISTINCT m.Uid)

Here is the HQL:

            select count(distinct m.Uid) 

            from Media m

            join m.Productlines p
            join m.Categories c                
            join m.Spaces sp
            join m.Solutions so

            where m.Uid != 0
            and p.Uid in (:productlines)
            and c.Uid in (13)                
            and sp.Uid in (52)
            and so.Uid in (15,18)

How can this be done with Criteria API?

Please, (N)Hibernate experts - help me with this, I cant find a working solution. Any help is greatly appreciated!

+1  A: 
var count = session.CreateCriteria(typeof(Media))
    // Add other criterias...
    .SetProjection(Projections.CountDistinct("Id")) // or whatever the id property of Media class is called
    .UniqueResult<long>();

As to your GROUP BY question, the query:

SELECT m.*
....
GROUP BY m.Uid

makes no sense because you need to select only columns that appear in the group by clause or aggregate functions. Could you elaborate a little more as to what exactly are you trying to achieve?

Darin Dimitrov
With that GROUP BY Uid I remove duplicates from the result set, which might occur when I add the joins on m.Productline etc.
Max
+1  A: 

Group columns are implicitly returned as result, but you can add more columns. AFAIK, you can return full entities:

var query = session.CreateCriteria(typeof(Media), "m")
  .Add(Projections.GroupProperty("m"))
  .Add(Restrictions.NotEq("m.Uid", 0));

// dynamically add filters
if (filterProductLines)
{
  query
    .CreateCriteria("m.Productlines", "p")
    .Add(Restrictions.Eq("p.Uid", productLines));
}
// more dynamic filters of this kind follow here...

IList<Media> results = query.List<Media>();

To count the full number of results you can just build up the same query with different projection:

var query = session.CreateCriteria(typeof(Media), "m")
    .SetProjection(Projections.CountDistinct("m.Uid"));
// rest of the query the same way as above

long totalNumberOfResults = query.UniqueResult<long>();


I'm getting unsure about the Projections.GroupProperty("m"), you need to try this. If it doesn't work, you could make it an DetachedQuery that only returns ids:

var subquery = DetachedCriteria.For(typeof(Media), "m")
  .Add(Projections.GroupProperty("m.Uid"))
  .Add(Restrictions.NotEq("m.Uid", 0));
// add filtering

var query = session.CreateCriteria(typeof(Media), "outer")
  .Add(Subqueries.PropertyIn("outer.Uid", subquery));

IList<Media> results = query.List<Media>();

This creates a sql query like this:

select outer.* // all properties of Media to create an instance
from Media outer
where outer.Uid in (
  select Uid
  from media m
  where // filter
)
Stefan Steinegger
Thank you for that detailed answer. However, the Projections.GroupProperty("m") does not seem to work?I tried to use the subquery, but that would cause a full table scan as it seems, which is not an option in this case.
Max
The exact error if I use the GroupProperty Method with ("m"):could not resolve property: m of: ...App.Models.Media
Max
Why does it cause a full table scan if it is in a subquery? You group by Media.Uid, which should have an index. I don't know why it is different if the same query is used in a subquery.
Stefan Steinegger
I dont know exactly why, but the above query does force a full table scan of the outer table, although Uid is indexed/the primary key. Maybe it is an mysql 5.1 issue.
Max
Accpeted solution because it got me in the right direction!
Max