2010-07-08 5 views
7

Encontré un caso bastante extraño en Java EE 6 donde el uso del método find de JPA EntityManager junto con el ID primario de una entidad devuelve nulo, pero usando los Criterios API para seleccionar todas las entidades con esa id funciona bien.EntityManager.find no puede encontrar entidad, pero al usar la API Criteria

Aquí está el código que estoy usando para find:

// Always returns null, even for records I know for sure are in there. 
user = em.find(User.class, userId); 

... y aquí está el código que estoy usando con la API Criterios:

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<User> criteria = builder.createQuery(User.class); 
Root<User> u = criteria.from(User.class); 
TypedQuery<User> query = em.createQuery(
    criteria.select(u).where(builder.equal(u.get("id"), userId))); 
user = query.getSingleResult(); 

idea de por qué vuelve find nulo pero Criteria encuentra al Usuario? Probé estos dos métodos alternativos exactamente en el mismo lugar del programa.

Estas son las partes pertinentes de la entidad Usuario:

@Entity 
@Table(name = "USERS") 
@Access(AccessType.PROPERTY) 
public class User implements Serializable { 
    ... 
    private Long id; 
    ... 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id_generator") 
    @SequenceGenerator(name = "user_id_generator", sequenceName = "user_sequence", allocationSize = 1) 
    @Column(name="id") 
    public Long getId() { 
     return this.id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 
    ... 
} 
+0

No estoy seguro de si esto hace la diferencia, pero ¿el ID de usuario es largo o tal vez es un número entero en tu código? –

+0

Es un largo, lo comprobé dos veces. – cdmckay

+0

Acabo de experimentar este problema con Hibernate 4.1.8.Final – molholm

Respuesta

11

Descubrí el problema. Fue debido a un campo en la base de datos que es null donde no debería haber sido permitido. Esto fue debido a que lo edité a mano. Después de que agregué un valor a ese campo, el problema desapareció.

+2

Es posible que desee aplicar NOT NULL para esa columna para salvaguardia futura. – ChuongPham

+0

saludos para compartir, salvó mi día – MarianP

+0

@ChuongPham: 100% de acuerdo. Esta no era mi base de datos, pero me enseñó el valor de usar restricciones para hacer cumplir la integridad de los datos;) – cdmckay

0

Una de las razones podría ser que el campo "id" no se ha marcado correctamente como el ID de usuario para la entidad.

3

¿Qué proveedor está utilizando?

¿Dónde está ejecutando este hallazgo, dentro o fuera de una transacción? ¿Estás enrojeciendo y limpiando el EM antes del hallazgo?

Usando EclipseLink como proveedor, y mi propio modelo similar, no puedo reproducir esto.

Suponiendo que su proveedor puede iniciar sesión en SQL, ¿ve que SQL va al DB en el buscador? ¿Cómo se ve el SQL y se ejecuta correctamente en SQL Plus, etc.

+0

Debería estar enjuagando el EM antes de encontrarlo? Estoy usando Hibernate como mi proveedor. – cdmckay

+0

Lo estoy ejecutando en un EJB '@ Stateless'. El EM está decorado con un '@PersistanceContext (unitName =" xxx_persistence ")'. Voy a referirme a los registros de SQL y ver qué puedo encontrar. – cdmckay

+0

Ok, comprobé el SQL y me sorprendió ver la diferencia entre las dos consultas: la versión "buscar" estaba haciendo un millar de combinaciones, mientras que la consulta de "criterios" solo estaba obteniendo de la tabla de usuarios. Alguien más escribió los archivos de la entidad, así que tendré que buscarlos para descubrir qué está causando esto. – cdmckay

0

Como un control de cordura, depure el código y dedique tiempo antes de ejecutar el descubrimiento para ejecutar una consulta manual en la base de datos usted mismo para asegurarse de que un registro de usuario apropiado está presente con la identificación que espera.

Si no está en la base de datos, asegúrese de que el administrador de entidades se haya purgado o la transacción actual se haya confirmado.

Por ejemplo, si está utilizando Hibernate como proveedor, es posible que el objeto "persista" simplemente en caché y los cambios no se hayan enviado a la base de datos. En consecuencia, los criterios que pasan por la implementación de Hibernate recuperarán el objeto, pero el hallazgo del administrador de entidades no podrá ubicar el objeto.

+0

Esta es una buena sugerencia, pero sé que no estaba siendo almacenada en caché porque podría consultarla en la base de datos incluso antes de iniciar la aplicación. – cdmckay

1

vuelve a comprobar que usted está pasando un Long en el siguiente fragmento:

// Always returns null, even for records I know for sure are in there. 
user = em.find(User.class, userId); 

Si esto no ayuda, activar el registro de SQL para ver lo que está sucediendo y comparar el comportamiento en ambos casos.

+0

Depuré y verifiqué que efectivamente era un Largo. – cdmckay

+0

@cdmckay: ejecuté su código de mi lado y no me puedo reproducir (como esperaba ser sincero). Probado con Hibernate EM 3.5.3-Final. –

+0

Sí, creo que tiene que ver con cómo se anota la entidad de usuario. – cdmckay

3

Confirmo la solución. Lo mismo me pasó a mí.Tenía collumnas marcadas como NOT NULL, luego, durante la prueba en mi aplicación, desconecté la limitación en la base de datos para dos columnas (claves externas), pero no cambié el atributo (optional = false) de la relación @ManyToOne en mi clase de entidad. Después de eliminar el atributo, para que el modelo fuera consistente con la base de datos, todo comenzó a funcionar bien. Es extraño que el entorno no produzca una advertencia o excepción de algún tipo.

Cuestiones relacionadas