简体   繁体   English

如何在子集合的Nhibernate中执行QueryOver

[英]How to do a QueryOver in Nhibernate on child collection

Hello I have one Class named Notifications which is a child class for the User. 您好我有一个名为Notifications的类,它是User的子类。

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; }
}

Now I want to get the User By ID which will bring all the notifications for the current user. 现在我想获取User By ID,它将为当前用户提供所有通知。

var user = NhSession.Get<User>(userId);

But I don't want to get all the notifications. 但我不想收到所有通知。 I just want to get the user with unread notifications and just want to get top 5 (Latest) notifications for the user. 我只想让用户获得未读通知,并且只想获得用户的top 5 (Latest) notifications

I tried to achieve that by joinQueryOver but I was not able to do that. 我尝试通过joinQueryOver实现这一点,但我无法做到这一点。 Can anyone please suggest to get this working. 任何人都可以建议让这个工作。

Based on the latest update and new Entity(ies) structure, we can now profit from Pairing object, and quickly select Users which has unread Notificaitons like this 基于最新的更新和新的Entity(ies)结构,我们现在可以从Pairing对象中获利,并快速选择具有未读Notificaitons的用户

Find users who have not read notifications 查找尚未阅读通知的用户

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>();

Find 5 unread notifications per userId 每个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>()

The session.Get<TEntity>(entityId) is there for us to load the Entity AS IS mapped. session.Get<TEntity>(entityId)用于我们加载实体AS IS映射。 That's the contract. 这是合同。

If we want to get filtered results, we have to use another contract to recive the data: Session.CreateCriteria() (or any other querying API ie QueryOver() ) 如果我们想要获得过滤结果,我们必须使用另一个合同来重新获取数据: Session.CreateCriteria() (或任何其他查询API,即QueryOver()

So in our case, we should build the query to find user with unread notifications: 所以在我们的例子中,我们应该构建查询以查找具有未读通知的用户:

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>();

What we can see here, is expectations (well in fact a MUST) that notification has back reference to its parent, to user: 我们在这里看到的是通知(实际上是必须的)通知已经向用户提及其父级:

public class Notification
{
    ...
    public User User {get;set;}
}

But that should not be an issue, it is just a mapping, not change in DB 但这应该不是问题,它只是一个映射,而不是DB的变化

Similar query (on top of Notification) we can use to get only first 5 of them: 类似的查询(在通知之上)我们可以使用它们只获得前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>()
;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM