I'm trying to express a SQL query using NHibernate's Criteria API, and I'm running into difficulty because I'm thinking in a database-centric way while NHibernate is object-centric.
SQL (works great):
select outerT.id, outerT.col1, outerT.col2, outerT.col3
from tbl outerT
inner join
(select max(innerT.id)
from tbl innerT
group by innerT.col1) grpT
on outerT.id = grpT.id
Essentially, this is a self-join of a table against a subset of itself. I suppose I could try turning the self-join into a restriction:
select outerT.id, outerT.col1, outerT.col2, outerT.col3
from tbl outerT
where outerT.id in (select max(innerT.id) from tbl innerT group by innerT.col1)
But I'm not sure how to express that using NHibernate either; I'm fighting with the DetachedCriteria's ProjectionList and wanting to select only max(id)
while grouping by col1
.
Thanks so much for your suggestions!
I don't know if I should post this as a new answer or to add it as a comment on the original question, but I think I've resolved a similar problem in this thread:
Selecting on Sub Queries in NHibernate with Critieria API
AFAIK you cannot join to subqueries at all in NHibernate but you can re-organise the query to use either an EXISTS or IN clause to replicate the same functionality.
I realise the question asks for this to be done using the Criteria API but I thought I would post a HQL version which may give someone else some ideas.
var results = session.CreateQuery("from Product p where p.Id in (
select max(p2.id)
from Product p2
group by p2.col1
)")
I also found this JIRA issue surrounding the Criteria API and not including group by columns in the select. Currently it looks like what you want cannot be achieved using the Criteria API at all.
Group By Property without adding it to the select clause
UPDATE Using the example from Monkey Coders post looks like you can do this:
var subquery = DetachedCriteria.For<Product>("p")
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty("p.Col1"))
.Add(Restrictions.EqProperty("p2.Id", Projections.Max("p.Id"));
var query = DetachedCriteria.For<Product>("p2")
.Add(Subqueries.Exists(subquery));
Which would produce the following SQL
select *
from Product p2
where exists (
select p.col1
from Product p
group by p.col1
having p2.Id=max(p.Id)
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With