2014-12-27 7 views
9

dostaję ten błąd przy składaniu formularza:Wolnostojący jednostka przeszła utrzymują error

org.hibernate.PersistentObjectException: wolnostojący jednostka przeszła do przetrwania: com.project.pmet.model.Account; wyjątek zagnieżdżonych jest javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: wolnostojący jednostka przeszła do przetrwania: com.project.pmet.model.Account

Oto moje podmioty:

konta:

@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; 

    ... 

zespołu:

@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; 

    ... 

Oto część kontrolera:

@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"; 
    } 

i formy:

<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> 

Co robię źle?

Odpowiedz

20
teamService.save(team); 

Metoda zapisywania akceptuje tylko obiekty przejściowe. Jaki jest przemijający obiekt można znaleźć

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).

otrzymujesz przedmiot zespołu i staramy się utrzymywać ją do DB, ale że obiekt ma obiekt konta w nim i że obiekt Konto jest odłączona (środki ta instancja tego obiektu zapisała się w DB, ale ten obiekt nie znajduje się w sesji). Hibernate stara się go uratować z powodu podałeś:

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

Tak, istnieje kilka sposobów, w jaki sposób można to naprawić:

1) Nie używaj konfiguracji CascadeType.ALL. Obiekt konta może być używany dla wielu zespołów (przynajmniej struktura domeny na to pozwala), a operacja aktualizacji może aktualizować konto dla wszystkich zespołów - oznacza to, że ta operacja nie powinna być inicjowana przy aktualizacji zespołu. Usunąłbym stąd kaskadowy parametr (domyślna wartość to nie operacje kaskadowe), jeśli naprawdę potrzebujesz użyć konfiguracji MERGE/DELETE. Ale jeśli naprawdę potrzebujesz go zatrzymać, zobacz opcję # 2

2) użyj metody "saveOrUpdate()" zamiast "save()". Metoda "saveOrUpdate()" przyjmuje przejściowe i odłączone obiekty. Ale problem z tym podejściem polega na projektowaniu: czy naprawdę trzeba wstawić/zaktualizować konto podczas zapisywania obiektu zespołu? Podzielę go na dwie operacje i zapobiegnę aktualizacji konta od zespołu.

Mam nadzieję, że to pomoże.

+0

Głosuj za pierwszym rozwiązaniem, które mi pomogło. – vtomic85

10

Błąd występuje, ponieważ ustawiono id. Hibernacja rozróżnia obiekty przejściowe i oderwane i działa tylko w przypadku obiektów przejściowych.

isteamService.save(team); 

w tej operacji nie można załadować id ponieważ jest @GeneratedValue

+1

To perfekcyjna odpowiedź, upewnij się, że id nie ma wartości. –

+1

Och, więc obiekty z identyfikatorem o wartości '@ GeneratedValue' nie mogą zostać zapisane, jeśli identyfikator jest już ustawiony? Pomyślałem, że ta adnotacja będzie tylko pewnego rodzaju powrotem. Dobrze wiedzieć, że nie jest! – Froxx

+1

Upewnij się, że twój id nie jest ustawiony na 0, jeśli typem danych jest "Integer" i jest w porządku, jeśli id ​​datatype to 'int'. – Ram

0

Ponieważ id jest automatycznie generowane wartości, nie wysyłaj go od strony klienta.Miałem ten sam problem. Upewnij się, że nie podajesz wartości atrybutu generowanego automatycznie.