2012-04-11 9 views
7

Ho bisogno di ottenere il conteggio delle righe da una query di criteri ei criteri sono raggruppati per proiezioni. (necessario per far funzionare il cercapersone)NHibernate, ottieni il conteggio quando i criteri hanno un gruppo di

E.g.

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

Ho bisogno di evitare CreateSQL, poiché ho molti criteri .. e le restrizioni, ecc. Sono complesse.

Si può fare una sottocriteria (staccata) e quindi select count(*) from ..? Non riesci a capire come?

MODIFICA: l'ho risolto prendendo lo sql dai criteri e quindi modificandolo in modo che ora funzioni! GetSql from criteria

+0

Mi piacerebbe fare la stessa cosa ... ma evitare la soluzione GetSql. –

+0

Sì, questa soluzione era dolorosa, necessaria per ottenere lo sql dai criteri ma non è possibile ottenere i parametri oi valori dai criteri (in modo semplice), quindi avevamo bisogno di un'altra raccolta per archiviare i valori, e hanno bisogno di essere nell'ordine corretto ecc. –

+0

Cosa hai inserito nell'SQL? Non riesco ancora a capire quale risultato ti serva. –

risposta

0

Penso che questo può essere fatto utilizzando NH Multi Queries.

Ecco alcune informazioni a riguardo: http://ayende.com/blog/3979/nhibernate-futures L'esempio mostra come possiamo eseguire query e ottenere il conteggio dei risultati di tale query in un roundtrip al database.

E qui c'è una buona risposta, che sembra simile a ciò che si desidera ottenere: nhibernate 2.0 Efficient Data Paging DataList Control and ObjectDataSource in cui ottengono la pagina dei risultati E il totale dei record conta in un roundtrip al database.

Inoltre, dubito che sia possibile leggere il valore puro @@rowcount con NH senza modificare query SQL, come @@rowcount è cosa specifica del database.

La mia ipotesi è che per il tuo caso non è possibile evitare la soluzione GetSql from criteria, a meno che non si semplifichi la query o l'approccio. Forse vale la pena provare anche questo.

Se è possibile inserire una parte più grande del codice, probabilmente qualcuno sarà in grado di capirlo.

+0

Questo funziona solo per query non complesse, il problema è che ho ottenuto query create con criteri che hanno raggruppato per proiezioni. Quando usi qualcuno degli helper o ti piacciono tutti gli esempi in rete, la query sql è solo sbagliata .. –

0

Non del tutto sicuro di quello che si vuole, ma qualcosa di simile dovrebbe funzionare (se ho capito la tua domanda correttamente):

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[]>(); 
+0

È qualcosa che ho proposto anch'io, ma vedi il commento sotto la mia risposta. –

0

solo pensare un po 'fuori dagli schemi e rimuovere la complessità query da NHiberate. È possibile creare una vista per la query nel database e quindi creare una mappatura per la vista.

0

Ho risolto questo problema nella versione java (Hibernate). Il problema è che la funzione RowProjection è un po 'come:

count(*) 

Quella è una funzione di aggregazione: quindi se si crea un 'gruppo da' immobile il risultato è una lista della riga raggruppata e per ogni riga si ha la conteggio totale del gruppo.

Per me, con database Oracle, per farlo funzionare ho creare una proiezione personalizzata che, invece di creare funzione count (*), la funzione è

count(count(*)) 

e la proprietà del gruppo da la clausola non viene scritta nella selezione ... dall'istruzione.Per fare che non è così semplice, il problema è che è necessario fornire tutte pila per creare lo sql destra in modo, con la versione Java ho a subclasse 2 classe: SimpleProjection ProjectionList

Dopo di che la mia domanda ha generato come:

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

diventano

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

e il risultato sono riga totale in

select col1, col2 from table1 group by col1, col2 

(utilizzabile con il sistema di impaginazione)

vi posto qui la versione Java delle classi, se sono utili per voi:

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

Spero che questo aiuto.

Problemi correlati