NHibernate,当条件有一个分组时获取rowcount

时间:2012-04-11 12:42:42

标签: nhibernate criteria

我需要从条件查询中获取行数,并且条件按投影分组。 (需要分页才能工作)

E.g。

projectionList.Add(Projections.GroupProperty("Col1"), "col1")
              .Add(Projections.CountDistinct("Col2"), "Count");

我需要避免使用CreateSQL,因为我有很多标准..而且限制等很复杂。

你能做一个子标准(分离)然后select count(*) from ..吗?想不出来怎么样?

编辑:我通过从标准中获取sql然后修改它来解决它,以便它现在可以正常工作! GetSql from criteria

4 个答案:

答案 0 :(得分:0)

我认为这可以通过使用NH Multi Queries来完成。

以下是关于它的一些内容:http://ayende.com/blog/3979/nhibernate-futures示例显示了我们如何在一次往返数据库中运行查询并获取该查询的结果计数。

这里有一个很好的答案,听起来与你想要达到的目标类似:nhibernate 2.0 Efficient Data Paging DataList Control and ObjectDataSource,他们得到结果页面,并且总记录数在一次往返数据库中计算。

另外,我怀疑可以在不更改sql查询的情况下使用NH读取纯@@rowcount值,因为@@rowcount是特定于数据库的东西。

我的假设是,对于您的情况,除非您简化查询或方法,否则无法避免GetSql from criteria解决方案。也许值得尝试一下。

如果您可以发布更大量的代码,可能有人能够解决这个问题。

答案 1 :(得分:0)

不完全确定你想要什么,但这样的事情应该有效(如果我理解你的问题):

var subQuery = DetachedCriteria.For<SomeClass>()
   .Where(... add your conditions here ...);

var count = Session.CreateCriteria<SomeClass>()
   .Where(Property.ForName("Col1").In(
      CriteriaTransformer.Clone(subQuery).SetProjection(Projections.Property("Col1"))
   .SetProjection(Projections.Count())
   .FutureValue<int>();

var results = subQuery.GetExecutableCriteria(Session)
            .SetProjection(Projections.GroupProperty("Col1"), "col1"),
                           Projections.CountDistinct("Col2"), "Count")
            ).List<object[]>();

答案 2 :(得分:0)

只是稍微考虑一下,从NHiberate中删除查询复杂性。您可以在数据库中为查询创建一个View,然后为该视图创建一个映射。

答案 3 :(得分:0)

我已经在java版本(Hibernate)上解决了这个问题。问题是RowProjection函数有点像:

count(*) 

这是一个聚合函数:所以如果你创建一个'group by'属性,你的结果就是一个分组行的列表,每行都有你的组总数。

对我来说,使用oracle数据库,为了使它工作,我创建了一个自定义投影,而不是创建函数计数(*),该函数是

count(count(*)) 

并且group by子句中的属性不会写入select ... from语句中。要做到这一点不是那么简单,问题是你必须提供所有堆栈来创建正确的sql所以,使用java版本我要继承2类: SimpleProjection ProjectionList

之后,我的查询生成为:

select count(*), col1, col2 from table1 group by col1, col2

成为

select count(count(*)) from table1 group by col1, col2

,结果是

给出的总行数
select col1, col2 from table1 group by col1, col2

(可与分页系统一起使用)

我在这里发布了java版本的类,如果对你有用:

public class CustomProjectionList extends ProjectionList {

    private static final long serialVersionUID = 5762155180392132152L;


    @Override
    public ProjectionList create() {
        return new CustomProjectionList();
    }

    public static ProjectionList getNewCustomProjectionList() {
        return new CustomProjectionList();
    }

    @Override
    public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery) throws HibernateException {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < getLength(); i++) {
            Projection proj = getProjection(i);
            String sqlString = proj.toSqlString(criteria, loc, criteriaQuery);
            buf.append(sqlString);
            loc += getColumnAliases(loc, criteria, criteriaQuery, proj).length;
            if (i < (getLength() - 1) && sqlString != null && sqlString.length() > 0)
                buf.append(", ");
        }
        return buf.toString();
    }

    private static String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery, Projection projection) {
        return projection instanceof EnhancedProjection ?
                ( ( EnhancedProjection ) projection ).getColumnAliases( loc, criteria, criteriaQuery ) :
                projection.getColumnAliases( loc );
    }


}

public class CustomPropertyProjection extends SimpleProjection {


    private static final long serialVersionUID = -5206671448535977079L;

    private String propertyName;
    private boolean grouped;


    @Override
    public String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
        return new String[0];
    }

    @Override
    public String[] getColumnAliases(int loc) {
        return new String[0];
    }

    @Override
    public int getColumnCount(Criteria criteria, CriteriaQuery criteriaQuery) {
        return 0;
    }


    @Override
    public String[] getAliases() {
        return new String[0];
    }

    public CustomPropertyProjection(String prop, boolean grouped) {
        this.propertyName = prop;
        this.grouped = grouped;
    }

    protected CustomPropertyProjection(String prop) {
        this(prop, false);
    }

    public String getPropertyName() {
        return propertyName;
    }

    public String toString() {
        return propertyName;
    }

    public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) 
    throws HibernateException {
        return new Type[0];
    }

    public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) 
    throws HibernateException {

        return "";
    }

    public boolean isGrouped() {
        return grouped;
    }

    public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
    throws HibernateException {
        if (!grouped) {
            return super.toGroupSqlString(criteria, criteriaQuery);
        }
        else {
            return StringHelper.join( ", ", criteriaQuery.getColumns( propertyName, criteria ) );
        }
    }

}

public class CustomRowCountProjection extends SimpleProjection {
    /**
     * 
     */
    private static final long serialVersionUID = -7886296860233977609L;


    @SuppressWarnings("rawtypes")
    private static List ARGS = java.util.Collections.singletonList( "*" );

    public CustomRowCountProjection() {
        super();
    }


    public String toString() {
        return "count(count(*))";
    }

    public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
        return new Type[] {
                getFunction( criteriaQuery ).getReturnType( null, criteriaQuery.getFactory() )
        };
    }

    public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) throws HibernateException {
        SQLFunction countSql = getFunction( criteriaQuery );
        String sqlString = countSql.toString() + "(" +  countSql.render( null, ARGS, criteriaQuery.getFactory() ) + ") as y" + position + '_';
        return sqlString;
    }

    protected SQLFunction getFunction(CriteriaQuery criteriaQuery) {
        SQLFunction function = criteriaQuery.getFactory()
                .getSqlFunctionRegistry()
                .findSQLFunction( "count" );
        if ( function == null ) {
            throw new HibernateException( "Unable to locate count function mapping" );
        }
        return function;
    }
}

希望得到这个帮助。