Hibernate Criteria API o Spring HibernateTemplate condición NOT IN no funciona ... o no sé aplicarlo.

Pues éso, resulta que ando queriendo hacer algo como, enviar un Set con objetos, y traerme todos los elementos que sean excluyentes a mi objeto seleccionado.

Ejemplo:

Tengo un objeto Service:

@Entity
@Table(name="SERVICES")
public class Service implements Serializable {
        private static final long serialVersionUID = 1L;

        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name="ID_SERVICE")
        private long id;

        //bi-directional many-to-many association to Task
        @ManyToMany(mappedBy="services", fetch=FetchType.LAZY)
        private Set<Task> tasks;
        .....
//blabla no importa, mas propiedades, y get y set de cada propiedad....
}

y objeto Device

@Entity
@Table(name="DEVICES")
public class Device implements Serializable {
        private static final long serialVersionUID = 1L;

        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name="ID_DEVICE")
        private long id;

        //bi-directional many-to-many association to Service
        @ManyToMany(mappedBy="devices", fetch=FetchType.EAGER)
        private Set<Service> services;
       .....
//blabla no importa, mas propiedades, y get y set de cada propiedad....

}

Bueno, ahora la famosa consulta, la hago de ésta forma, con HibernateTemplate:

        public List<Service> loadOuterServicesByDevices(final Set<Device>devices) {
                StringBuilder sql = new StringBuilder();
                sql.append(" from Service service " );
                sql.append(" join service.devices devices where devices not in (:devices) ");
                List<Service> services = hibernateTemplate.findByNamedParam(sql.toString(), "devices" , devices);
                return services;
        }

O bien de ésta forma, con Criteria:

        public List<Service> loadOuterServicesByDevices(final Set<Device>devices) {
                final List<Service> services = hibernateTemplate.execute( new HibernateCallback<List<Service>>() {
                        @Override
                        public List<Service> doInHibernate(Session session)throws HibernateException, SQLException {

                                Criteria criteria = session.createCriteria(Service.class);
                                criteria.add( Restrictions.not( Restrictions.in( "devices", devices)));
                                criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
                                return criteria.list();
                        }
                });
                return services;
        }

Bueno, el punto es, que si lo aplico con HibernateTemplate(la primer forma) la lista viene vacía ( y sí tengo registros )
y si lo aplico de la segunda, me avienta <sarcasmo>una graciosa y bien documentada excepción</sarcasmo>

GRAVE: >>org.springframework.jdbc.UncategorizedSQLException: Hibernate operation: could not execute query; uncategorized SQLException for SQL [select this_.ID_SERVICE as ID1_21_1_, this_.[ALIAS] as ALIAS2_21_1_, this_.ID_SERVICE_TYPE as ID6_21_1_, this_.CHECK_TYPE as CHECK3_21_1_, this_.NAME as NAME21_1_, this_.UPDATE_DATETIME as UPDATE5_21_1_, catservice2_.ID_SERVICE_TYPE as ID1_0_0_, catservice2_.NAME as NAME0_0_ from dbo.SERVICES this_ left outer join dbo.CAT_SERVICE_TYPE catservice2_ on this_.ID_SERVICE_TYPE=catservice2_.ID_SERVICE_TYPE where not this_.ID_SERVICE in (?)]; SQL state [null]; error code [0]; El valor no está configurado para el número de parámetro 1.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: El valor no está configurado para el número de parámetro 1.
[SQL: 0, null]
>>com.microsoft.sqlserver.jdbc.SQLServerException: El valor no está configurado para el número de parámetro 1.
>>      at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(Unknown Source)
>>      at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.buildParamTypeDefinitions(Unknown Source)
>>      at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.buildPreparedStrings(Unknown Source)
>>      at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doPrepExec(Unknown Source)
>>      at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(Unknown Source)
>>      at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(Unknown Source)
>>      at com.microsoft.sqlserver.jdbc.TDSCommand.execute(Unknown Source)
>>      at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(Unknown Source)
.......

Y bueno, pues ya anduve buscando qué onda, pero no he hallado nada, alguien ha hecho algo semejante?
Acepto propuestas, ya sea con Spring o con Hibernate.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de neko069

Meh...

Pues la consulta terminó siendo de éste modo.

        public List<Service> loadOuterServicesByDevices(final Set<Device>devices) {
                log.info( "GlobalServiceDaoImpl.loadOuterServicesByDeviceId" );

                final StringBuilder sql = new StringBuilder();
                sql.append(" SELECT ser.* FROM SERVICES ser WHERE ID_SERVICE NOT IN ");
                sql.append(" (SELECT ID_SERVICE FROM DEVICE_SERVICE WHERE ID_DEVICE NOT IN(:devices)) ");
               
                List<Service> services = hibernateTemplate.execute( new HibernateCallback<List<Service>>() {
                        @Override
                        public List<Service> doInHibernate(Session session)throws HibernateException, SQLException {
                                Query query = session.createSQLQuery(sql.toString()).addEntity(Service.class);
                                query.setParameterList( "devices", devices);
                                return query.list();
                        }
                });
                return services;
        }

Como consulta de SQL (nativa pues) y bueno, pues con éso.