2015-07-09 11 views
7

Sto sviluppando un'applicazione che utilizza riposo primavera e Hibernate e voglio ottenere i record nidificate dal database come sto ottenendo Profession per un User, ora voglio andare a prendere Users associato alla Profession I recuperato in precedenza.Come recuperare entità associate a Hibernate

Qui è la mia classe Dao

@SuppressWarnings({ "unchecked", "rawtypes" }) 
public List<Profession> getProfessionById(long id) throws Exception { 
    session = sessionFactory.openSession(); 
    Criteria cr = session.createCriteria(Profession.class); 
    cr.add(Restrictions.eq("uid", id)); 
    List results = cr.list(); 
    tx = session.getTransaction(); 
    session.beginTransaction(); 
    tx.commit(); 
    return results; 
} 
+0

Criteri cr = session.createCriteria (User.class); cr.add (Restrictions.eq ("pid", pid)); Elenco risultati = cr.list(); Potresti anche aggiornare la domanda con la mappatura e la relazione ER tra Professione e Utente? Credo che con la sua mappatura ManyToMany, in questo caso, puoi utilizzare EAGER FETCH nel tuo stesso codice e otterrai direttamente gli utenti associati all'oggetto Profession. – pratikpawar

+0

Puoi spiegare in questo caso qual è la richiesta di REST? – gabrielgiussi

+0

Risponderai al controllo. – ozgur

risposta

2

Recupero Strategie

Ci sono quattro che vanno a prendere strategie

  1. fetch- “join” = Disabilitare il lazy loading, sempre caricare tutto il collezioni ed entità.
  2. fetch- "select" (predefinito) = Lazy carica tutte le raccolte e le entità.
  3. batch-size = "N" = recupero fino a raccolte o entità "N", Non registrare.
  4. fetch- "subselect" = Raggruppa la sua raccolta in un'istruzione sub select.

Per la spiegazione dettagliata, è possibile controllare la documentazione di Hibernate.

FetchType.LAZY è su richiesta

FetchType.EAGER è immediato

@SuppressWarnings({ "unchecked", "rawtypes" }) 
public List<User> getProfessionById(long id) throws Exception { 
    session = sessionFactory.openSession(); 
     Criteria cr = session.createCriteria(Profession.class, "pro") 
          .setFetchMode("user", FetchMode.JOIN); 
     cr.add(Restrictions.eq("uid", id)); 
     Profession pro = cr.uniqueResult(); 
     tx = session.getTransaction(); 
     session.beginTransaction(); 
     tx.commit(); 
    return pro.getUsers(); 
} 
+0

dove sarà usato? –

+0

non capisco .. – ozgur

+0

dove dovrei scrivere questo codice? –

0

Potreste essere in grado di utilizzare il seguente:

criteri di Hibernate
Criteria cr = session.createCriteria(Profession.class); 
cr.setFetchMode("user", FetchMode.EAGER); 
cr.add(Restrictions.eq("uid", id)); 
List results = cr.list(); 

Non ho usato, ma un rapido google si avvicinò con qualcosa di simile.

1

Secondo la query, la tabella Professione ha una colonna uid che è probabilmente un FK per la tabella Users e penso che la tabella Users debba avere un FK per la Professione.

Quindi la tabella Users avrà un many-to-one associazione ad un Profession:

@ManyToOne 
private Profession profession; 

e la Profession può associare tutti gli Utenti che hanno quella particolare professione, così nell'entità Profession si ha il lato inverso di questa associazione:

@OneToMany(mappedBy = "profession") 
private List<Users> users = new ArrayList<>(); 

ora per ottenere tutti gli utenti di avere una professione è possibile eseguire una semplice query come questa:

List<Users> users = (ist<Users>) session.createQuery(
    "select u " + 
    "from Profession p " + 
    "join fetch p.users u " + 
    "where p.id = :id") 
.setParameter("id", proffesionId) 
.list(); 
+0

Penso che un utente possa avere molte professioni, perché sta restituendo una lista quando sta cercando da user_id nella tabella delle professioni . – gabrielgiussi

2

Prima di tutto bisogna aggiungere sotto mappatura Professione e l'entità utente classe

In Professione classe

//bi-directional many-to-one association to Users 
@OneToMany(mappedBy="profession", cascade=CascadeType.ALL) 
private List<User> users; 

public List<User> getUsers() { 
    return this.users; 
} 

public void setUsers(List<User> users) { 
    this.users = users; 
} 

In classe entità User

@ManyToOne(fetch=FetchType.EAGER) 
@JoinColumn(name="profession_id") 
private Profession profession; 

Poi si può andare a prendere oggetto professione per id utilizzando il codice di classe DAO esistente.

@SuppressWarnings({ "unchecked", "rawtypes" }) 
public List<Profession> getProfessionById(long id) throws Exception { 
    session = sessionFactory.openSession(); 
    Profession profession = (Profession) session.get(Profession.class, id); 

    // here you can get list of users for this profession 
    // List<User> users = profession.getUsers(); 
    return profession; 
} 
2

penso che si sta facendo qualcosa di sbagliato nella tua classe DAO perché si sono aperti una sessione e una transazione all'interno del vostro metodo e, probabilmente, in ognuno di metodi del DAO.

Se ciò comporta un costo in termini di prestazioni ed è poco concettuale, una transazione deve raggruppare un insieme di operazioni che avranno esito positivo o negativo. Nella maggior parte dei casi una transazione di database sarà correlata a un'intera operazione aziendale, in questo caso una richiesta REST. Qualcosa di simile

POST/utente

@ RestController.createUser

transazione aperta

UserDAO.saveUser

commit della transazione

risposta

Inoltre, se si guarda il codice si sta aprendo una transazione e poi si chiude.

tx = session.getTransaction(); 
session.beginTransaction(); 
tx.commit(); 

In questo caso si sta interrogando il database in modo che non sia necessaria alcuna transazione.

Le transazioni sono una preoccupazione trasversale nella vostra applicazione e, dato che state già utilizzando Spring, dovreste esaminare l'annotazione @Transactional (o il suo equivalente xml) per ottenere una transazione con AOP (Spring crea un aspetto aroud). Ciò renderebbe il tuo codice molto più leggibile e mantenibile.

La risposta di @ManojP ha una buona e una cattiva cosa. Penso che dovresti evitare le relazioni bidirezionali ogni volta che puoi perché rende più difficile il design. Il mio consiglio è questo: iniziare sempre con relazioni unidirezionali e se hai trovato un caso in cui non puoi evitarlo, usalo.La cosa buona è che sta mostrando a voi l'uso di pigrizia quando lo fa:

List<User> users = profession.getUsers(); 

Questa riga di codice dovrebbe essere al di fuori del DAO. Quello che succede è che hai un elenco di utenti contrassegnati come pigri (è l'impostazione predefinita), quindi quando recuperi le professioni con la query dei criteri, viene attivata una selezione sulle professioni della tabella e ognuno degli oggetti Professione viene creato con un raccolta proxy invece della raccolta vera. Quando chiami profession.getUsers() una nuova selezione viene innescata sulla tabella degli utenti dove professione_id = professione.getId(). Quindi:

  1. Elenco risultati = criteria.list();
  2. Seleziona * dalla professione
  3. professionA.getUsers();
  4. Select * from utente in cui profession_id =: professionA.getId()

Ma attenzione! se si dispone di una collezione di professioni (come penso che si deve perché si sta tornando una lista) e iterazioni su ogni professione e chiedere l'elenco degli utenti faresti:

  1. risultati list = criteria.list();
  2. Select * from Professione
  3. per ogni professione -> profession.getUsers
  4. select * from utente in cui profession_id =: professionA.getId()
  5. Select * from utente in cui profession_id =: professionB.getId()

Questo avrà una prestazione negativa.

La risposta di @farvilain è buona. Ma in questo caso recupererai sempre una Professione con la sua collezione di Utenti perché all'interno del tuo DAO usi sempre FetchMode.JOIN, e quindi stai perdendo il beneficio della pigrizia. Quindi, se vuoi sempre la lista degli utenti quando stai interrogando Professions, usa lazy = true per la raccolta di utenti, ma sii consapevole dei costi che possono avere (se l'utente ha una raccolta non pigro A quando si interroga Professions recupererai anche l'elenco degli utenti più la raccolta A). Se non si desidera che questo, forse si potrebbe avere questa firma:

public List<Profession> getProfessionById(Long id, FetchMode fetchMode) throws Exception 

Questo non è molto bello, ma mostra che il client DAO potrebbe scegliere la modalità fecth.

1

A partire dal codice

@SuppressWarnings({ "unchecked", "rawtypes" }) 
public List<Profession> getProfessionById(long id) throws Exception { 
    session = sessionFactory.openSession(); 
    Criteria cr = session.createCriteria(Profession.class); 
    cr.add(Restrictions.eq("uid", id)); 
    List results = cr.list(); 
    tx = session.getTransaction(); 
    session.beginTransaction(); 
    tx.commit(); 
    return results; 
} 

ho vi proporrò di utilizzare Transactionnal annotazione se si sta utilizzando di primavera. Rende il codice più chiaro. Quindi smetti di usare SuppressWarnings, è uggly e inutile, puoi configurare il tuo IDE per nasconderli.

@Transactionnal(readonly = true) 
public List<Profession> getProfessionById(long id) throws Exception { 
    Criteria cr = session.createCriteria(Profession.class); 
    cr.add(Restrictions.eq("uid", id)); 
    List results = cr.list(); 
    return results; 
} 

Inutile dal fatto che i criteri sono API fluenti e non creano variabili locali, ora non è più necessario.

@Transactionnal(readonly = true) 
public List<Profession> getProfessionById(long id) throws Exception { 
    return session 
     .createCriteria(Profession.class) 
     .add(Restrictions.eq("uid", id)) 
     .list(); 
} 

Facciamo ora risolvere il problema

@Transactionnal(readonly = true) 
public List<Profession> getProfessionById(long id) throws Exception { 
    return session 
     .createCriteria(Profession.class) 
     .add(Restrictions.eq("uid", id)) 
     .setFetchMode("users", FetchMode.JOIN) 
     .list(); 
} 

Richiede ovviamente questa linea in professione;

public class Profession { 
    [...] 

    @OneToMany(mappedBy = "profession") 
    private Set<Users> users = new HashSet<>(); 

    [...] 
} 

Attenzione

Non hai bisogno di getter/setter, non chiamare la mappatura inversa quando uneeded.

Assicuratevi di non usare Elenco, Hibernate non è molto gradito Elenco senza dichiarazione di ordine.

Non dichiarare gli utenti come ricercati nell'entità, si verificherà un terribile problema ogni volta che si carica una professione di proprietà di molti utenti, anche se non si è pronti a recuperarli da soli.

Non utilizzare FetchMode.EAGER, è deprecato!

0

Utilizzare ManyToMany mapping per ottenere le professioni, in modo che anche gli utenti assottigliati vengano a provarlo. link.

Problemi correlati