2011-01-21 7 views
9

Quando il livello aziendale crea una nuova entità, che rappresenta logicamente un'istanza di un'entità esistente che deve essere aggiornata (diciamo che condivide la stessa chiave aziendale), questo è il metodo per fondere le cattive pratiche?unione di un'entità distaccata o nuova con un'entità esistente nella domanda di best practice hibernate/jpa

public User add(User user){ 

    User existingUser = getUserDao().findByBusinessKey(user.getBusinessKey(), false); 
    user.setId(existingUser.getId()); 

    user = getUserDao().merge(user); 

    return user; 
} 

Lo chiedo perché l'impostazione del ID esplicitamente sull'entità staccato si sente abbastanza strano per me, ma anche se il metodo equals e hashCode dell'entità utente siano adeguatamente implementato, impostando l'ID qui è l'unico modo per garantire l'unione ha luogo.

Esiste una pratica migliore?

Ci sono specifici inconvenienti a questo metodo che mi morderebbero più tardi?

Grazie per dare un'occhiata!

+1

Una cosa che il mio frammento di codice non dimostrava era la definizione di getUserer(). Unire (utente) il risultato al riferimento utente originale ... aggiornando lo snippet per dimostrarlo. –

+0

Perché avere un ID (generato automaticamente) e una chiave aziendale in primo luogo? Perché non utilizzare la chiave Busines come ID? Ciò presuppone che non cambi mai, naturalmente .. – bert

+0

È sempre stata la raccomandazione del team di ibernazione da ciò che ho letto - e sembra funzionare bene nella maggior parte delle situazioni, tranne quella che ho posto: s http: // community.jboss.org/wiki/EqualsandHashCode –

risposta

2

Questo codice verrà lavoro, ma impostando l'ID in modo esplicito per l'entità indipendente non dovrebbe essere necessario. Una tipica app di Hibernate ha un metodo "salva" che gestisce due casi:

  1. L'utente desiderava creare un nuovo utente, quindi l'applicazione crea un oggetto Utente con 'null' come ID.
  2. L'utente ha richiesto un elenco di utenti e ne sta selezionando uno per la modifica. In questo caso l'app esegue una query e propaga l'oggetto al metodo "salva". L'oggetto avrà un ID e il codice applicherà nuovi valori ad esso.

Sembra che qualcosa nel codice non stia facendo il secondo caso nel modo tipico. Se l'oggetto "utente" proviene da una precedente query Hibernate (attivata dall'utente che fa clic su "modifica utente" o qualcosa del genere), allora avrà già un ID. Pertanto, è necessaria solo la chiamata merge(user).

faccio di solito qualcosa di simile:

if (user.getId() == null) 
    em.persist(user); 
else 
    user = em.merge(user); 

poi aggiungo il codice per gestire i problemi ottimistiche di bloccaggio (un'altra sessione aggiornato l'oggetto) e problemi di vincolo univoco (un'altra sessione ha provato a persistere qualcosa con la stessa chiave di business).

I framework come Seam lo rendono ancora più semplice perché propagano la sessione di Hibernate tra i metodi del bean controller. Quindi anche l'unione non è necessaria.

+0

equivale a "unire" incondizionatamente? Oltre a restituire una copia dell'oggetto, 'merge' può fare tutto ciò che fa' persist'. –

+0

IIRC, l'unione è un superset di persist. Non uso più unire più da quando ho iniziato a utilizzare Seam. –

0

Se la tua entità è un'entità distaccata, l'unica cosa che devi veramente fare è invocare entityManager.merge (utente). Non è necessario eseguire alcun metodo di ricerca. Se la tua entità non è staccata ma piuttosto nuova (non ha ID specificato) dovresti trovare l'entità appropriata nel database prima di eseguire qualsiasi operazione di modifica su quell'entità e unirla in seguito. cioè:

User user = userDao.findBySomething(Criteria c); 

//stuff that modifies user 

user = userDao.merge(user); 
+0

Immagino che il mio problema sia il 2 ° caso che menzioni. A meno che non imposti esplicitamente l'id sulla nuova istanza dell'entità, l'unione non ha esito positivo. Questo ha senso se l'unico modo in cui l'entityManager sa fondersi sta usando l'identificatore, ma io pensavo che avrebbe dovuto capire .equals(). In caso contrario, e continuo a impostare l'ID, incontrerò qualche altro problema? –

+1

I metodi equals() e hashCode() dovrebbero * mai * presumere che l'ID sia impostato, devono sempre usare la chiave aziendale. Il problema è che in qualche modo l'istanza distaccata non ha un ID (rendendolo * transitorio *, non separato). Vedi la mia risposta sopra. –