Reputation: 5190
Given the model Activity containing a bag with models of type Report (one to many). I would like to get a list of all activities, containing the number of reports of each activity. This two queries don't lead to any good, the counter is always 1 (which is wrong):
select act, (select count(r) from act.Reports r) from Activity act
Or:
select act, count( elements(act.Reports) ) from Activity act group by act.ActivityId, act.Title
Is it possible to write a proper query in HQL to solve this easy task?
Thx for any tipps! sl3dg3
Edit: Following the mappings. Activity:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class
name="Core.Models.Config.Activity, Core"
table="Activity"
>
<!-- primary key -->
<id name="ActivityId" type="Int32" unsaved-value="0" access="property">
<column name="ActivityId" not-null="true"/>
<generator class="identity" />
</id>
<!-- Properties -->
<many-to-one name="Title" fetch="join" cascade="all"/>
<!-- One-To-Many Reports -->
<bag name="Reports" inverse="true" fetch="join">
<key column="ReportId" />
<one-to-many class="Core.Models.Report"/>
</bag>
</class>
</hibernate-mapping>
Mapping Report:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class
name="Core.Models.Report, Core"
table="Report"
>
<!-- primary key -->
<id name="ReportId" type="Int32" unsaved-value="0" access="property">
<column name="ReportId" not-null="true"/>
<generator class="identity" />
</id>
<!-- Properties (shortened - there are more many-to-one and one bag -->
<property name="Created" />
<many-to-one name="Activity" column="ActivityId" />
</class>
Class Activity:
public class Activity
{
public Activity()
{
Title = new Translation();
}
public virtual int ActivityId { get; set; }
public virtual Translation Title { get; set; }
public virtual IList<Report> Reports { get; set; }
}
Class Report:
public class Report
{
/// <summary>
/// HNIBERNATE ONLY
/// </summary>
public Report()
{ }
/// <summary>
/// Init Report
/// </summary>
public Report(User author)
{
// ... Shortened
Activity = new Activity();
}
public virtual Activity Activity { get; set; }
}
Upvotes: 1
Views: 1597
Reputation: 64628
What you want to achieve is something like this in SQL:
select
act.*,
(select count(*) from Reports rep where rep.id = act.reportId)
from Activity act
It would be easiest using size()
, but unfortunately this is not working:
select act, size(act.Reports)
from Activity act
According to the docs, size
is not available in the select clause. Interestingly, it actually works with .size
, but not with size()
, which should actually be equivalent:
select act, act.Reports.size
from Activity act
It may be worth a feature request to also make the function syntax (size()
) working.
The officially working group by syntax is cumbersome, because you need to group by all mapped Activity properties:
select act, count(*)
from Activity act left join act.Reports rep
group by act.id, act.Name, act.Whatever
So I tried finally this variant and it seems to be exactly what you need:
select act, (select count(*) from act.Reports)
from Activity act
Upvotes: 2
Reputation: 5362
Your first HQL query has the wrong syntax. Try this instead:
select act, (select count(*) from act.Reports) from Activity act
Your second HQL query cannot work, because you would need all the columns in the GROUP BY clause. Try this instead:
select act.ActivityId, act.Title, count( elements(act.Reports) )
from Activity act
group by act.ActivityId, act.Title
Edit:
Ah, I think this might be the bug:
<bag name="Reports" inverse="true" fetch="join">
<key column="ActivityId" /> <-- instead of ReportId
<one-to-many class="Core.Models.Report"/>
</bag>
Upvotes: 1