2014-12-27 29 views
9

sto ottenendo questo errore quando l'invio del modulo:un'entità indipendente passò a persistere errore

org.hibernate.PersistentObjectException: un'entità indipendente passato a persistere: com.project.pmet.model.Account; l'eccezione annidata è javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: un'entità indipendente passata a persistere: com.project.pmet.model.Account

qui sono i miei soggetti:

Account:

@Entity 
@DynamicInsert 
@DynamicUpdate 
public class Account { 

    @Id 
    @GeneratedValue 
    private Integer id; 

    @Column(nullable = false) 
    private String login; 

    @Column(nullable = false) 
    private String password; 

    @Column(nullable = false) 
    private String email; 

    @ManyToOne 
    @JoinColumn(name = "team_id") 
    private Team team; 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner") 
    private List<Team> ownedTeams; 

    ... 

della squadra:

@Entity 
@DynamicInsert 
@DynamicUpdate 
public class Team { 

    @Id 
    @GeneratedValue 
    private Integer id; 

    @Column(nullable = false) 
    private String name; 

    @ManyToOne 
    @JoinColumn(name = "owner_id", nullable = false) 
    private Account owner; 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "team") 
    private List<Account> members; 

    ... 

Ecco una parte del controller:

@ModelAttribute("team") 
    public Team createTeamObject() { 
     return new Team(); 
    } 

    @RequestMapping(value = "/teams/create-team", method = RequestMethod.GET) 
    public String getCreateTeam(@ModelAttribute("team") Team team, Principal principal) { 
     logger.info("Welcome to the create team page!"); 

     Account owner = accountService.findOneByLogin(principal.getName()); 
     team.setOwner(owner); 
     team.setMembers(new AutoPopulatingList<Account>(Account.class)); 

     return "teams"; 
    } 

    @RequestMapping(value = "/teams/create-team", method = RequestMethod.POST) 
    public String postCreateTeam(@ModelAttribute("team") Team team) { 
     logger.info("Team created!"); 

     teamService.save(team); 

     return "redirect:/teams.html"; 
    } 

E la forma:

<form:form commandName="team" id="teamForm"> 
     <div class="form-group"> 
      <label>Name</label> 
      <form:input path="name" cssClass="form-control" /> 
     </div> 
     <div class="form-group" id="row-template"> 
      <label>Members</label> 
      <form:select path="members[0].id" cssClass="form-control" data-live-search="true" > 
      <form:options items="${accounts}" itemValue="id" /> 
      </form:select> 
      ... 
     </div> 
    <form:hidden path="owner.id" /> 
</form:form> 

Che cosa sto facendo di sbagliato?

risposta

20
teamService.save(team); 

Il metodo di salvataggio accetta solo oggetti transitori. Qual è l'oggetto transiente si possono trovare

Transient - an object is transient if it has just been instantiated using the new operator, and it is not associated with a Hibernate Session. It has no persistent representation in the database and no identifier value has been assigned. Transient instances will be destroyed by the garbage collector if the application does not hold a reference anymore. Use the Hibernate Session to make an object persistent (and let Hibernate take care of the SQL statements that need to be executed for this transition).

Hai trovato l'oggetto della squadra e si sta cercando di persistere al DB, ma quell'oggetto ha oggetto account in esso e che oggetto account è staccato (mezzo quell'istanza di quell'oggetto è stata salvata nel DB ma quell'oggetto non è nella sessione). Hibernate sta cercando di salvare a causa di aver specificato:

@OneToMany(cascade = CascadeType.ALL, .... 

Quindi, ci sono alcuni modi come è possibile risolvere il problema:

1) Non utilizzare la configurazione CascadeType.ALL. L'oggetto account può essere utilizzato per il numero di team (almeno la struttura del dominio lo consente) e l'operazione di aggiornamento potrebbe aggiornare Account per TUTTI i team: ciò significa che questa operazione non deve essere avviata con l'aggiornamento del team. Vorrei rimuovere da lì il parametro cascade (il valore di default non è operazioni in cascata), se davvero hai bisogno di usare la configurazione MERGE/DELETE. Ma se hai davvero bisogno di persistere allora vedi l'opzione # 2

2) usa il metodo 'saveOrUpdate()' invece di 'save()'. Il metodo 'saveOrUpdate()' accetta oggetti transitori e staccati. Ma il problema con questo approccio è in fase di progettazione: è necessario inserire/aggiornare l'account quando si salva l'oggetto Team? Lo dividerei in due operazioni e impedire l'aggiornamento dell'account dal team.

Spero che questo aiuti.

+0

Vota per la prima soluzione, che mi ha aiutato. – vtomic85

10

L'errore si verifica perché è impostato l'ID . Hibernate distingue tra oggetti transienti e distaccati e funziona solo con oggetti transitori.

isteamService.save(team); 

in questa operazione non può essere caricato id perché è @GeneratedValue

+1

Questa è la risposta perfext, assicurati che l'id non abbia valore. –

+1

Oh, quindi gli oggetti con un id che ha un valore '@ GeneratedValue' non possono essere salvati nemmeno se quell'id è già impostato? Pensavo che l'annotazione sarebbe stata solo una sorta di ripiego. Buono a sapersi, non lo è! – Froxx

+1

Assicurati che l'ID non sia impostato su 0 se il tuo tipo di dati è 'Intero' e va bene se il tipo di dati id è' int'. – Ram

0

Dal momento che il id viene automaticamente valore generato, non inviare dal lato client.Ho avuto lo stesso problema. Assicurati di non fornire un valore per l'attributo generato automaticamente.