如何在 Nhibernate 中对子集合进行 QueryOver
Posted
技术标签:
【中文标题】如何在 Nhibernate 中对子集合进行 QueryOver【英文标题】:How to do a QueryOver in Nhibernate on child collection 【发布时间】:2014-12-15 05:55:32 【问题描述】:您好,我有一个名为 Notifications 的类,它是用户的子类。
public class User
public int Id get; set;
public string Name get; set;
public string UserName get; set;
public ICollection<UserNotification> UserNotifications get; set;
public class Notification
public int Id get; set;
public ICollection<UserNotification> UserNotifications get; set;
public string Title get; set;
public string Message get; set;
public bool IsRead get; set;
public DateTime CreatedDate get; set;
public class UserNotification
public User User get; set;
public Notification Notification get; set;
现在我想通过 ID 获取用户,它将为当前用户带来所有通知。
var user = NhSession.Get<User>(userId);
但我不想收到所有通知。我只想让用户收到未读通知,只想为用户获取top 5 (Latest) notifications
。
我试图通过 joinQueryOver 来实现,但我无法做到。任何人都可以建议让这个工作。
【问题讨论】:
【参考方案1】:基于最新的更新和新的Entity(ies)结构,我们现在可以从Pairing对象中获利,并快速选择有类似这样未读Notificaitons的用户
查找未阅读通知的用户
var session = NHSession.GetCurrent();
Notification notification = null;
UserNotification pair = null;
User user = null;
var subquery = QueryOver.Of<UserNotification>(() => pair)
// this will give us access to notification
// see we can filter only these which are NOT read
.JoinQueryOver(() => pair.Notification, () => notification)
// here is the filter
.Where(() => !notification.IsRead)
// now the trick to take only related to our user
.Where(() => pair.User.Id == user.Id)
// and get the user Id
.Select(x => pair.User.Id);
var listOfUsers = session.QueryOver<User>(() => user)
.WithSubquery
.WhereProperty(() => user.Id)
.In(subquery)
// paging
.Take(10)
.Skip(10)
.List<User>();
为每个 userId 查找 5 个未读通知
var userId = 1;
var subqueryByUser = QueryOver.Of<UserNotification>(() => pair)
// now we do not need any kind of a join
// just have to filter these pairs related to user
.Where(() => pair.User.Id == userId)
// and get the notification Id
.Select(x => pair.Notification.Id);
var notificationsPerUser = session.QueryOver<Notification>(() => notification)
.WithSubquery
.WhereProperty(() => notification.Id)
.In(subqueryByUser)
.Where(() => !notification.IsRead)
// if needed we can order
// .OrderBy(...
.Take(5)
.List<Notification>()
【讨论】:
如果这有帮助并且有效,先生!真的。享受这个强大的工具;) 我一直在努力解决这个问题好几个小时了,你的解释很简单,评论也很好。谢谢,干得好!【参考方案2】:session.Get<TEntity>(entityId)
可以让我们加载 AS IS 映射的实体。这就是合同。
如果我们想获得过滤结果,我们必须使用另一个合约来接收数据:Session.CreateCriteria()
(或任何其他查询 API,即QueryOver()
)
因此,在我们的例子中,我们应该构建查询以查找具有未读通知的用户:
Occupation Notification= null;
User user = null;
var subquery = QueryOver.Of<Notification>(() => notification)
.Where(() => !notification.IsRead )
// just related to the user, from outer query
.Where(() => notification.User.ID == user.ID)
.Select(x => notification.User.ID);
var list = session.QueryOver<User>(() => user)
.WithSubquery
.WhereProperty(() => user.ID)
.In(subquery)
// paging
.Take(10)
.Skip(10)
.List<User>();
我们在这里可以看到,期望(实际上是必须的)通知回溯到它的父级和用户:
public class Notification
...
public User User get;set;
但这不应该是一个问题,它只是一个映射,而不是数据库中的变化
类似的查询(在 Notification 之上),我们只能获取其中的前 5 个:
var notifications = session.QueryOver<Notification>(() => notification)
// here is a userId for a specific user.
// we can use IN() to load for more of them
.Where(() => notification.User.ID != userId)
.Take(5)
.List<Notification>()
;
【讨论】:
我看到您已经为通知创建了一个新的 queryOver,但是如果我只想在主查询中获取 5 个通知怎么办?还获得按日期排名前五的订单。 也是对其父级的引用,我没有公共用户 User get;set; 但我有 ICollectionmany-to-many
处理查询,(我个人强烈反对:see)。以上是关于如何在 Nhibernate 中对子集合进行 QueryOver的主要内容,如果未能解决你的问题,请参考以下文章
如何在Fluent NHibernate中映射受保护的集合?