【问题标题】:NHibernate: hql to criteria query - help neededNHibernate:hql 到标准查询 - 需要帮助
【发布时间】:2009-09-17 12:34:57
【问题描述】:

我有这个 hql 查询,效果很好:

            select m 

            from Media m

            join m.Productlines p
            join m.Categories c                
            join m.Spaces sp
            join m.Solutions so

            where m.Uid != 0
            and p.Uid in (:productlines)
            and c.Uid in (13)                
            and sp.Uid in (52)
            and so.Uid in (15,18)

            group by m.Uid

但是现在它需要参数化/动态化,不仅是参数,还有连接(可以只从 Media 中选择,没有任何连接,因此在这种情况下不需要 *.Uid in )。

我不想弄乱 StringBuilder 实例并以这种方式构建 hql 查询,我宁愿使用 Criteria API,但我无法获得

SELECT m.*
....
GROUP BY m.Uid

查询以使用标准。

如果我添加一个

Projections.GroupProperty("Uid") 

对于我的查询,休眠选择

SELECT m.Uid
....
GROUP BY m.Uid

这当然是错误的。

之后,我还需要计算查询返回的 unique 行,因为结果是分页的。

所以,我的其他查询非常相似,但我找不到与

等效的条件
SELECT COUNT(DISTINCT m.Uid)

这是 HQL:

            select count(distinct m.Uid) 

            from Media m

            join m.Productlines p
            join m.Categories c                
            join m.Spaces sp
            join m.Solutions so

            where m.Uid != 0
            and p.Uid in (:productlines)
            and c.Uid in (13)                
            and sp.Uid in (52)
            and so.Uid in (15,18)

如何使用 Criteria API 做到这一点?

请 (N)Hibernate 专家 - 帮我解决这个问题,我找不到可行的解决方案。非常感谢任何帮助!

【问题讨论】:

    标签: c# nhibernate


    【解决方案1】:

    组列作为结果隐式返回,但您可以添加更多列。 AFAIK,您可以返回完整的实体:

    var query = session.CreateCriteria(typeof(Media), "m")
      .Add(Projections.GroupProperty("m"))
      .Add(Restrictions.NotEq("m.Uid", 0));
    
    // dynamically add filters
    if (filterProductLines)
    {
      query
        .CreateCriteria("m.Productlines", "p")
        .Add(Restrictions.Eq("p.Uid", productLines));
    }
    // more dynamic filters of this kind follow here...
    
    IList<Media> results = query.List<Media>();
    

    要计算全部结果数,您可以使用不同的投影构建相同的查询:

    var query = session.CreateCriteria(typeof(Media), "m")
        .SetProjection(Projections.CountDistinct("m.Uid"));
    // rest of the query the same way as above
    
    long totalNumberOfResults = query.UniqueResult<long>();
    

    我不确定Projections.GroupProperty("m"),你需要试试这个。如果它不起作用,您可以将其设为仅返回 id 的 DetachedQuery:

    var subquery = DetachedCriteria.For(typeof(Media), "m")
      .Add(Projections.GroupProperty("m.Uid"))
      .Add(Restrictions.NotEq("m.Uid", 0));
    // add filtering
    
    var query = session.CreateCriteria(typeof(Media), "outer")
      .Add(Subqueries.PropertyIn("outer.Uid", subquery));
    
    IList<Media> results = query.List<Media>();
    

    这会创建一个这样的 sql 查询:

    select outer.* // all properties of Media to create an instance
    from Media outer
    where outer.Uid in (
      select Uid
      from media m
      where // filter
    )
    

    【讨论】:

    • 感谢您的详细回答。但是, Projections.GroupProperty("m") 似乎不起作用?我尝试使用子查询,但这似乎会导致全表扫描,在这种情况下这不是一个选项。
    • 如果我使用带有 ("m") 的 GroupProperty 方法的确切错误:无法解析属性:m of: ...App.Models.Media
    • 为什么在子查询中会引起全表扫描?您按 Media.Uid 分组,它应该有一个索引。我不知道为什么在子查询中使用相同的查询会有所不同。
    • 我不知道具体原因,但上面的查询确实强制对外部表进行全表扫描,尽管 Uid 是索引/主键。可能是 mysql 5.1 的问题。
    【解决方案2】:
    var count = session.CreateCriteria(typeof(Media))
        // Add other criterias...
        .SetProjection(Projections.CountDistinct("Id")) // or whatever the id property of Media class is called
        .UniqueResult<long>();
    

    关于您的 GROUP BY 问题,查询:

    SELECT m.*
    ....
    GROUP BY m.Uid
    

    没有意义,因为您只需要选择出现在 group by 子句或聚合函数中的列。您能否详细说明您想要实现的目标是什么?

    【讨论】:

    • 使用 GROUP BY Uid 我从结果集中删除重复项,当我在 m.Productline 等上添加连接时可能会发生这种情况。
    猜你喜欢
    • 2020-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多