Comparando coleções com hibernate

Bom dia a todos!

Tenha as seguinte entidades:

public class Imagem {
    private Integer id;
    private Evento evento;
    private Set<Classificador> classificadores = new HashSet();
...
}

public class Classificador {
    private Integer id;
    private String nome;
    private Set<Imagem> imagens = new HashSet();
...
}

public class Evento {
    private Integer id;
    private Set imagens = new HashSet();
    private String descricao;
    private Date data;
...
}

devidamente mapeados com os hbms:

    <class name="bean.Imagem">
        
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <many-to-one name="evento" class="bean.Evento" not-null="true"/>
        <set name="classificadores" table="ImagemClassificada" inverse="true">
            <key column="imagem"/>
            <many-to-many column="classificador" class="bean.Classificador"/>
        </set>        
    </class>

    <class name="bean.Classificador">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="nome"/>
        <set name="imagens" table="ImagemClassificada">
            <key column="classificador"/>
            <many-to-many column="imagem" class="bean.Imagem"/>
        </set>
    </class>

    <class name="bean.Evento">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="descricao"/>
        <property name="data"/>
        <set name="imagens" inverse="true" cascade="save-update">
            <key column="evento"/>
            <one-to-many class="bean.Imagem"/>
        </set>
    </class>

O que quero é obter instancias de Imagem por evento e classificador. Consigo retornar os classificadores de uma imagem “imagem.getClassificadores()”, as imagens de um classificador “classificador.getImagens()”, as imagens que casam com uma coleção de eventos:

public static List<Imagem> list(List<Evento> eventos) {
...
        Criteria criteria = session.createCriteria(Imagem.class);
        criteria.createAlias("evento", "evento");
        criteria.add( Restrictions.in("evento", eventos) );
        imagens = criteria.list();
...
}

O que não estou conseguindo é retornar as imagens em que os seus classificadores contenham uma dada coleção de classificadores. Exemplo:

classificadores -> c1, c2, c3, c4, c5

imagens -> img1, img2, img3

(img1 -> c1, c2, c3, c4), (img2 -> c1, c2, c3), (img3 -> c1, c4)

Digamos que eu queira as imagens que tenham como classificadores c1 e c4, deveria retornar (img1 e img3). Para a coleção de classificadores c2 e c4, deveria retornar (img1). Para a coleção de classificadores c1, deveria retornar (img1, img2 e img3).

Como resolvo isto?

Muito obrigado pela atenção amigos.

List< Classificador > classificadores = new ArrayList< Classificador >();
classificadores.add( new Classificador( 1 ) ); // pk
classificadores.add( new Classificador( 2 ) ); // pk
classificadores.add( new Classificador( 3 ) ); // pk

Criteria c = session.createCriteria( Imagem.class );
c.add( Restrictions.in( "classificadores", classificadores ) );
c.list();

Obrigado pela atenção LIPE, mas eu já havia tentando isto e retorna o seguinte:

Exception in thread "AWT-EventQueue-0" org.hibernate.exception.GenericJDBCException: could not execute query
        at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.loader.Loader.doList(Loader.java:2147)
        at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2028)
        at org.hibernate.loader.Loader.list(Loader.java:2023)
        at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:95)
        at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1569)
        at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
        at dao.ImagemDAO.list(ImagemDAO.java:93)
...
Caused by: java.sql.SQLException: Statement parameter 1 not set.
        at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1032)
        at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:677)
        at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1222)
        at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:186)
        at org.hibernate.loader.Loader.getResultSet(Loader.java:1668)
        at org.hibernate.loader.Loader.doQuery(Loader.java:662)
        at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
        at org.hibernate.loader.Loader.doList(Loader.java:2144)
        ... 31 more

Meu código:

        List<Imagem> imagens;
        Criteria criteria = session.createCriteria(Imagem.class);
        criteria.add(Restrictions.in("classificadores", classificadores));
        imagens = criteria.list();

Creio que o problema estaja no Resctrictions.in, pois creio que ele verifique se UM valor está em uma coleção, e não se uma coleção está contida em outra.

Que coisa chata! Novamente obrigado pela atenção.

Ah, faz sentido, apressado eu. :smiley:
Vou continuar a pesquisa aqui.

Hm, só encontrei gambiarras fazendo mapeamento da tabela da intersecção, no seu caso ImagemClassificada.
Então seria possível fazer a query que sugeri.

Mas deve ter outro jeito.

lendo o codigo na diagonal, me parece que voce esta precisando de Disjunction/Conjunction. Deve resolver.

Poxa Paulo :smiley: Nunca tinha usado esses.
Restrictions.disjunction()

criteria.add( Restrictions.disjunction().add( Restrictions.eq( "classificador", classificador1 ) ).add( Restrictions.eq( "classificador", classificador2 ) ) );

Apesar de achar bem melhor que a outra solução, ainda acho bem feio também.

Hum… vou tentar! Já retorno…

Não funciona também, dá o mesmo erro anterior… Acho que novamente é problema em Restrictions, pois deste jeito estou tentando igualar uma coleção (classificadores), com uma instancia… Restrictions.eq( “classificadores”, classificador1 )…

Vou continuar na pesquisa aqui também.

Valeu a força.

tentativa do Orseni:

Criteria cri = session.createCriteria(Imagem.class);
cri.createCriteria("classificadores", "c1")
   .add(Restriction.in("c1", colecao1)
   .createCriteria("images")
   .createCriteria("classificadores", "c2")
   .add(Restriction.in("c2", colecao2)

O pior é que não entendi esta tentativa do Orseni… :D, o que significa colecao1 e colecao2, tenho uma colecao de classificadores que pretendo verificar se está contida em na coleção de classificadores de cada imagem…

Fico no aguardo. Obrigado

O meu trecho de código ficou assim:

    public static List<Imagem> list(List<Classificador> classificadores) {
        List<Imagem> imagens;
        Session session = HibernateUtil.getSession();
        Criteria criteria = session.createCriteria(Imagem.class);
        criteria
        .createCriteria("classificadores", "c1").add(Restrictions.in("c1", classificadores)).createCriteria("imagens")
        .createCriteria("classificadores", "c2").add(Restrictions.in("c2", classificadores));

Mas deu o erro abaixo, creio que ele montou um sql errado, pois está usando somente a tabela classificador.

Hibernate: select classifica0_.id as id4_, classifica0_.nome as nome4_ from Classificador classifica0_ order by classifica0_.nome
Exception in thread "AWT-EventQueue-0" org.hibernate.QueryException: could not resolve property: c1 of: bean.Classificador

Obrigado

então não entendi direito…
vc tem uma colecao de classificadores e quer todas as imagens que tenham essa colecao entre a sua colecao de classificadores?

Ops… Desculpe a demora… Tive que resolver alguns problemas…

É exatamente isto, quero obter todas as imagens em que sua coleção de classificadores tenham uma dada coleção de classificadores.

Valeu!