我正在处理的项目中存在以下问题。系统中的每个事务都分配给给定用户。因此,事务和用户之间存在多对一关系,如下所示:
public class User
{
public int ID { get; private set; }
public string FirstName { get; set; }
....
}
public class Transaction
{
public int ID { get; private set; }
public User CreatedBy { get; private set; }
...
}
我已经使用NHibernate映射了这些实体,因此Transaction和User类之间存在多对一的映射。 User对象没有事务列表,但Transaction具有对创建它的用户的引用。
现在我想查询以检索创建了大多数事务的用户列表,但我无法弄清楚如何使用NHibernate获得前10个最多引用的用户。
有什么想法吗?我希望能够使用ICriteria来完成此操作而不是HQL,但如果需要,HQL就可以了。
更新
我尝试了sirrocco的查询建议......
DetachedCriteria topReferencedUsers = DetatchedCriteria.For(typeof(Transaction))
.SetProjection(Projections.GroupProperty("CreatedBy.Id"))
.SetProjection(Projections.Count("CreatedBy.Id").As("pcount" ))
.AddOrder(Order.Desc("pcount"))
.SetMaxResults(10);
并将其构建为子查询...
GetSession().CreateCriteria(typeof (User))
.Add(Subqueries.PropertyIn("Id", topReferencedUsers))
.List<User>();
但是此子查询不进行分组,但返回事务总数,然后将其用作User查询的IN子句。如果我用两个投影添加ProjectionList(),我得到了我想要的子查询的输出,但它失败了,因为它试图将两列输出运行到User查询的IN子句中。如何让NHibernate同时投影ID和Count,但只加入ID?
更新(2)
我尝试了Sirrocco的SqlGroupProjection建议(谢谢Sirrocco),但是空了。首先,它给了我错误,说它无法找到属性pcount,这意味着我需要删除顺序,这意味着它是按一些时间戳排序,这将无法正常工作。但即使如此,它仍然只输出用户被引用的次数,而不是用于加入Users表的用户ID。有任何想法吗?感谢。
答案 0 :(得分:1)
你可以自己尝试一下,看看你是否得到了想要的输出。
var userIds = this.Session
.CreateQuery(@"
select a.User.Id
from Transaction as a
group by a.User
order by count(a.User) desc")
.SetMaxResults(10)
.List<int>().ToArray();
var users = this.Session.CreateCriteria(typeof(User))
.Add(Restrictions.InG("Id", userIds))
.List<Artist>();
return users;
我从第一次查询获得的userId是(90,22,50,55)但是当传递给第二个查询时,我以22,50,55,90的顺序获取用户。
答案 1 :(得分:0)
您可以将操作分为两个步骤。
1)执行topReferencedUsers,然后将CreatedBy.Id投影提取到内存中的int数组中(因为你只处理10)。
2)然后执行:
GetSession().CreateCriteria(typeof(User))
.Add(Expression.InG<int>("Id", topTenIdArray))
.List<User>();