Domanda

Come è possibile, devo seguenti criteri

Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();

La dimensione della lista è ora 20. Se posso aggiungere un massimo di risultati per i criteri,

Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setMaxResults(90);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();

.. ora le dimensioni di lista è 18!

Non capisco come la dimensione di risultati può essere più piccolo dopo aver definito i risultati massimi, come la quantità di righe è più piccolo del massimo definito. Questo sembra sicuro come un insetto, o c'è ancora alcuni aspetti strani di Hibernate che io non sono a conoscenza?


Se siete alla ricerca di una risposta a questa domanda, assicuratevi di leggere la risposta accettata e le sue osservazioni.

È stato utile?

Soluzione

Quello che sta accadendo qui può essere visto molto chiaramente accendendo debug SQL in Hibernate e confrontando le query generate.

Utilizzando un abbastanza semplice SaleItem uno-a-molti mappatura (che è si spera auto-esplicativo), una query Criteria-based in questo modo:

Criteria c = sessionFactory.getCurrentSession().createCriteria(Sale.class);
c.createAlias("items", "i");
c.add(Restrictions.eq("i.name", "doll"));
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.setMaxResults(2);

produce SQL come questo:

select top ? this_.saleId as saleId1_1_, ... 
from Sale this_ 
inner join Sale_Item items3_ on this_.saleId=items3_.Sale_saleId 
inner join Item items1_ on items3_.items_id=items1_.id 
where items1_.name=?

mentre un Query in questo modo:

Query q = sessionFactory.getCurrentSession().createQuery("select distinct s from Sale s join s.items as i where i.name=:name");
q.setParameter("name", "doll");
q.setMaxResults(2);

produce qualcosa come:

select top ? distinct hibernated0_.saleId as saleId1_ 
from Sale hibernated0_ 
inner join Sale_Item items1_ on hibernated0_.saleId=items1_.Sale_saleId 
inner join Item hibernated2_ on items1_.items_id=hibernated2_.id 
where hibernated2_.name=?

Si noti la differenza nella prima riga (DISTINCT). Un ResultTransformer come DISTINCT_ROOT_ENTITY è una classe Java, che elabora i risultati delle file SQL dopo viene eseguito il codice SQL. Pertanto, quando si specifica un maxResults, che si intende applicare come limite fila sulla SQL; SQL include un join sugli elementi del Collection, quindi si sta limitando il risultato SQL a 90 sub-elementi . Una volta che il trasformatore DISTINCT_ROOT_ENTITY viene applicata, che può risultare in meno di 20 elementi radice, puramente dipende da quale radice elementi capita di uscire prima nei 90 risultati uniti.

DISTINCT in HQL comporta molto diverso, dal fatto che in realtà utilizza il DISTINCT parola chiave SQL, che viene applicato prima il limite di riga. Pertanto, questo si comporta come ci si aspetta, e spiega la differenza tra il 2.

In teoria si dovrebbe guardare setProjection di applicare una proiezione a livello di SQL - qualcosa come c.setProjection(Projections.distinct(Projections.rootEntity())) - ma purtroppo Projections.rootEntity() non esiste, ho appena fatto in su. Forse si deve!

Altri suggerimenti

Spero che questo può essere di aiuto

public List<Employee> getData(int to, int from) {

    Criteria hCriteria = null;
    List<Employee> viewDataList = null;
    List<Employee> exactDataList = null;
    try {

        hSession = HibernateSessionFactory.getSession();
        hTransaction = hSession.beginTransaction();
        hCriteria = hSession.createCriteria(Employee.class);

        /*
        hCriteria.setFirstResult(to);
        hCriteria.setFirstResult(from);
        */
        hCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        viewDataList = hCriteria.list();

        // for limit
        exactDataList=viewDataList.subList(from,to);

        hTransaction.commit();
    } catch (Exception e) {
        hTransaction.rollback();

    } finally {
        try {
            hSession.flush();
            HibernateSessionFactory.closeSession();
        } catch (Exception hExp) {
        }

}

    return exactDataList;
}

Un'altra soluzione è il seguente:

  1. eseguire il criteria.list() senza impostare alcun alias => i set / lista del soggetto principale riferimento sarà riempito con i proxy => Qui è possibile impostare correttamente i massimi risultati e quali
  2. eseguire i criteri alias sul proprio nella stessa sessione di sospensione => le deleghe di cui sopra verranno inizializzate

Qualcosa di simile a questo:

Criteria criteria = this.getSession().createCriteria(User.class);
criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
criteria.setMaxResults(10);

// First get the results without joining with the other tables
List<User> results = criteria.list();

// at this point the set roles is filled with proxies
// we'll now create and execute the join so these proxies are filled since we're still in the same session
getSession().createCriteria(User.class, "u")
        .createAlias("u.roles", "r", CriteriaSpecification.LEFT_JOIN)
        .list();

return results;

Spero che questo può aiutare,
Stijn

Questo è un problema noto in sospensione. Guardate @Cowan per uno SQL generato e una spiegazione del problema. C'è una richiesta di bug aperti per questo nel loro JIRA. La speranza di lasciare che qualcuno arriva e lo fissa:)

https://hibernate.atlassian.net/browse/HB-520

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top