【问题标题】:How to do a QueryOver in Nhibernate on child collection如何在 Nhibernate 中对子集合进行 QueryOver
【发布时间】: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 来实现,但我无法做到。任何人都可以建议让这个工作。

【问题讨论】:

    标签: c# nhibernate queryover


    【解决方案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&lt;TEntity&gt;(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;} 但我有 ICollection 因为我有很多与用户和通知有关的条件
    • 似乎我没有解释;(所以:1)如果您想查找只有未读通知的用户,请使用我的第一个查询和子查询。最后,您有干净的用户列表。 2)对于以这种方式加载的每个用户,创建第二个查询(我在回答中向您展示)以仅加载 5 个通知(您可以再次过滤它们以仅加载未读)。 3) 如果你想过滤它们,从通知到用户的映射是必须的。希望现在更清楚......
    • 我明白你的意思,但问题是我在通知中有 ICollection。我已经更新了我的域。请看一下
    • 我现在明白了!信不信由你,我们仍然可以用我的方法做到这一点。只是查询会稍微复杂一些......简单地说,原则将保持不变 - 只需使用many-to-many 处理查询,(我个人强烈反对:see
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多