2010-07-08 10 views
7

Ho riscontrato un caso piuttosto strano in Java EE 6 dove l'uso del metodo find di EntityManager di JPA insieme all'ID principale di un'entità restituisce null, ma utilizzando i criteri API per selezionare tutte le entità con quell'id funziona bene.EntityManager.find non trova l'entità, ma utilizzando l'API Criteri fa

Ecco il codice che sto utilizzando per find:

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

... ed ecco il codice che sto utilizzando con l'API Criteri:

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(); 

Qualsiasi idea del perché find rendimenti null ma Criteria trova l'utente? Ho provato questi due metodi alternativi nello stesso identico punto del programma.

Qui ci sono le porzioni rilevanti del entità User:

@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

Non sono sicuro se questo fa la differenza, ma userId un valore Long o forse un intero nel tuo codice? –

+0

È un lungo, l'ho ricontrollato. – cdmckay

+0

Ho appena sperimentato questo problema con Hibernate 4.1.8.Final – molholm

risposta

11

Ho capito il problema. Era dovuto al fatto che un campo nel database era null dove non avrebbe dovuto essere autorizzato. Ciò era dovuto al fatto che io lo stavo modificando a mano. Dopo aver aggiunto un valore a quel campo, il problema è andato via.

+2

Si potrebbe voler applicare NOT NULL per quella colonna per future salvaguardie. – ChuongPham

+0

evviva per la condivisione, salvata la mia giornata – MarianP

+0

@ ChuongPham: 100% d'accordo. Questo non era il mio database, ma mi ha insegnato il valore dell'utilizzo dei vincoli per imporre l'integrità dei dati;) – cdmckay

0

Una ragione potrebbe essere che il campo "id" non è stato correttamente contrassegnato come l'id per l'entità dell'utente.

3

Quale fornitore utilizza?

Dove stai eseguendo questa ricerca, dentro o fuori una transazione? Stai lavando e svuotando l'EM prima del ritrovamento?

Utilizzando EclipseLink come fornitore e il mio modello simile, non sono in grado di riprodurlo.

Supponendo che il provider possa registrare SQL, stai vedendo SQL accedere al DB nel find? Che aspetto ha l'SQL, e viene eseguito correttamente in SQL Plus ecc ...

+0

Dovrei essere a livello EM prima del ritrovamento? Sto usando Hibernate come mio fornitore. – cdmckay

+0

Lo sto eseguendo in un bean '@ Stateless'. La EM è decorata con un '@PersistanceContext (unitName =" xxx_persistence ")'. Ho intenzione di fare riferimento ai registri SQL e vedere cosa riesco a trovare. – cdmckay

+0

Ok, ho controllato l'SQL e sono rimasto molto sorpreso nel vedere la differenza tra le due query: la versione "trova" stava facendo un miliardo di join mentre la query "criteri" veniva acquisita solo dalla tabella degli utenti. Qualcun altro ha scritto i file dell'entità, quindi dovrò scavare tra quelli per scoprire che cosa sta causando questo. – cdmckay

0

Come controllo di integrità, eseguire il debug del codice, impiegando il tempo prima dell'esecuzione del find per eseguire manualmente una query sul database per assicurarsi che un record utente appropriato è presente con l'ID che ci si aspetta.

Se non è presente nel database, assicurarsi che il gestore entità sia stato svuotato o che la transazione corrente sia stata eseguita.

Ad esempio, se si utilizza Hibernate come provider, è possibile che l'oggetto sia "persistuto" solo nella cache e che le modifiche non siano state effettivamente trasferite al database. Di conseguenza, i criteri che attraversano l'implementazione di Hibernate recupereranno l'oggetto, ma il gestore dell'entità non sarà in grado di localizzare l'oggetto.

+0

Questo è un buon suggerimento, ma so che non è stato memorizzato nella cache perché potrei andare a cercare nel database prima ancora di aver avviato l'app. – cdmckay

1

Doppio controllo che si passa un Long nel seguente frammento:

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

Se questo non risolve il problema, attivare la registrazione SQL per vedere cosa sta succedendo e confrontare il comportamento in entrambi i casi.

+0

Ho eseguito il debug e controllato che fosse davvero un lungo. – cdmckay

+0

@cdmckay: Ho eseguito il codice dalla mia parte e non riesco a riprodurlo (come previsto per essere onesto). Testato con Hibernate EM 3.5.3-Final. –

+0

Sì, penso che abbia a che fare con come l'entità Utente è annotata. – cdmckay

3

Confermo la soluzione. La stessa cosa è successa a me.Avevo collumns contrassegnati come NOT NULL, quindi durante il test nella mia app ho disattivato la limitazione nel database per due colonne (chiavi esterne), tuttavia non modificando l'attributo (optional = false) della relazione @ManyToOne nella mia classe di entità. Dopo aver eliminato l'attributo, quindi il modello era coerente con il database, tutto ha iniziato a funzionare correttamente. Strano che l'ambiente non produca un avvertimento o un'eccezione di qualche tipo.

Problemi correlati