2013-09-09 2 views
0

В моей модели сущности 3 (в режиме реального времени более чем 3, но 3 на самом деле в этой ситуации)org.hibernate.NonUniqueObjectException. Как это исправить?

  1. кандидат
  2. Вакансия
  3. Событие

Все они имеют отношение многих к многие (у Кандидата могут быть вакансии и много событий, вакансий ... кандидатов и ... событий .....).

Если я обновляю кандидатуру - хороший результат. , если я обновлю Вакансия - хороший результат НО, если я обновлю событие У меня есть org.hibernate.NonUniqueObjectException

Это показывает, когда я меняю коллекцию вакансий в Событии. Если я комментирую место, где я изменить вакансии случае у меня нет никаких проблем (места ONE в моем коде) Перейти к коду: модели отображения:

Вакансия:

@Entity 
@Table(name = "vacancy") 
@XmlRootElement(name="vacancy") 
public class Vacancy { 

    private Integer id; 

    private String name; 

    private String description; 

    private Date date; 

    private User author; 

    @XmlTransient 
    private Set<Candidate> candidates = new HashSet<Candidate>(); 
    private Set<VacancyStatus> statusList = new HashSet<VacancyStatus>(); 
    private Set<Skill> skills = new HashSet<Skill>(); 
    private Set<Note> comments = new HashSet<Note>(); 
    private Set<Event> events = new HashSet<Event>(); 

    public Vacancy() { 
     super(); 
    } 

    @ManyToMany(mappedBy = "vacancies", fetch = FetchType.EAGER) 
    public Set<Event> getEvents() { 
     return events; 
    } 

    public void setEvents(Set<Event> events) { 
     this.events = events; 
    } 




    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "id") 
    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 



    @ManyToMany(mappedBy = "vacancies", fetch = FetchType.EAGER) 
    public Set<Candidate> getCandidates() { 
     return candidates; 
    } 

    public void setCandidates(Set<Candidate> candidates) { 
     this.candidates = candidates; 
    } 


    @Override 
    public boolean equals(Object obj) { 
     if(obj!= null && ((Vacancy)obj).getId() == id){ 
      return true; 
     } 
     return false; 
    } 
    @Override 
    public int hashCode() { 
     Integer id = getId(); 
     return id != null ? id.intValue() : super.hashCode(); 
    } 
    ... 
} 

Кандидат:

@Entity 
@Table(name = "candidate") 
@XmlRootElement(name = "candidate") 
public class Candidate extends Person { 

    @Size(min=3,max=12) 
    @Pattern(regexp="[0-9]*",message="phone format must be without + and - (for example: 89123353456)") 
    private String phone; 

    @Past 
    private Date date; 

    private User author; 

    @Size(min=4, max=100) 
    @URL() 
    private String resumeUrl; 

    private List<CandidateStatus> statusList = new LinkedList<CandidateStatus>(); 

    private Set<Vacancy> vacancies= new HashSet<Vacancy>(); 

    private Set<Skill> skills = new HashSet<Skill>(); 

    private List<Note> comments = new LinkedList<Note>(); 

    private Set<Event> events = new HashSet<Event>(); 

    public Candidate() { 
     super(); 
    } 

    @ManyToMany(mappedBy = "candidates", fetch = FetchType.EAGER) 
    //@LazyCollection(LazyCollectionOption.FALSE) 
    public Set<Event> getEvents() { 
     return events; 
    } 

    public void setEvents(Set<Event> events) { 
     this.events = events; 
    } 


    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    @JoinTable(name = "candidate_vacancy", joinColumns = @JoinColumn(name = "candidate_id"), inverseJoinColumns = @JoinColumn(name = "vacancy_id")) 
    @XmlTransient 
    public Set<Vacancy> getVacancies() { 
     return vacancies; 
    } 

    public void setVacancies(Set<Vacancy> vacancies) { 
     this.vacancies = vacancies; 
    } 
... 

} 
@MappedSuperclass 
public abstract class Person { 

    @Size(min=3) 
    @Pattern(regexp="[a-zA-Z]*")  
    private String name; 

    @Size(min=3) 
    @Pattern(regexp="[a-zA-Z]*") 
    private String surname; 

    private Integer id; 

    public Person() { 
    } 

    public Person(String name, String surname) { 
     super(); 
     this.name = name; 
     this.surname = surname; 
    } 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column (name = "id") 
    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    @Column(name = "name") 
    //@NotEmpty 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @Column(name = "surname") 
    //@NotEmpty 
    public String getSurname() { 
     return surname; 
    } 

    public void setSurname(String surname) { 
     this.surname = surname; 
    } 
    @Override 
    public boolean equals(Object obj) { 
     if(obj!=null && ((Person)obj).getId() == id){ 
      return true; 
     } 
     return false; 
    } 

    @Override 
    public int hashCode() { 
     Integer id = getId(); 
     return id != null ? id.intValue() : super.hashCode(); 
    } 




} 

Событие:

@Entity 
@Table(name = "event") 
@XmlRootElement 
public class Event { 
    private Integer id; 

    @Size(min=3) 
    @Pattern(regexp="[a-zA-Z]*")  
    private String name; 

    @Size(min=5) 
    @Pattern(regexp="[a-zA-Z]*")  
    private String description; 

    private Date date; 

    @Future 
    private Date eventDate; 

    private User author; 

    private Set<Candidate> candidates; 
    private Set<Vacancy> vacancies; 

    private EventType eventType; 
    private EventStatus eventStatus; 

    public Event() { 
     super(); 
    } 



    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name ="id") 
    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 


    @Override 
    public boolean equals(Object obj) { 
     if(obj!=null && ((Event)obj).getId() == id){ 
      return true; 
     } 
     return false; 
    } 
    @Override 
    public int hashCode() { 
     Integer id = getId(); 
     return id != null ? id.intValue() : super.hashCode(); 
    } 

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    public Set<Candidate> getCandidates() { 
     return candidates; 
    } 

    public void setCandidates(Set<Candidate> candidates) { 
     this.candidates = candidates; 
    } 

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    public Set<Vacancy> getVacancies() { 
     return vacancies; 
    } 

    public void setVacancies(Set<Vacancy> vacancies) { 
     this.vacancies = vacancies; 
    } 
} 

В моем @Controller классе я пишу так метод:

@RequestMapping(value = "/updateEvent", method = RequestMethod.POST) 
    public String updateEvent(Model model, 
      @Valid @ModelAttribute("existedEvent") Event event, 
      BindingResult result, 
      @ModelAttribute("linkedCandidates") Set<Candidate> candidates, 
      @ModelAttribute("linkedvacancies") Set<Vacancy> vacancies) { 
     if (result.hasErrors()) { 
      model.addAttribute("idEvent", event.getId()); 
      return "eventDetails"; 
     } 
     if (vacancies != null) { 
      for (Vacancy vacancy : vacancies) { 
       vacancy.getEvents().add(event); 
      } 
     } 
     if (candidates != null) { 
      for (Candidate candidate : candidates) { 
       candidate.getEvents().add(event); 
      } 
     } 
     event.setVacancies(vacancies);//place ONE (if comment this line - will //work) 
     event.setCandidates(candidates); 
     eventService.update(event);//error here 
     return "redirect:goToEventMenu"; 

    } 

обновление:

@Transactional 
@Service 
public class EventService { 
    public void update(Event event) { 
     eventDao.update(event); 
    } 
.... 
} 

@Repository("eventDaoImpl") 
public class EventDaoImpl extends DaoAbstract implements EventDao { 
    @Autowired 
    CandidateDao candidateDao; 

    @Autowired 
    VacancyDao vacancyDao; 



    @Override 
    public boolean update(Event event) { 
     Session session = sessionFactory.getCurrentSession(); 
     if (event == null) { 
      return false; 
     } 
     session.update(event); 
     return true; 
    } 
... 
} 

Извините за много кода/Но я не знаю, что писать здесь)

UPDATE 1

StackTrace:

10.09.2013 11:46:14 org.apache.catalina.core.StandardWrapperValve invoke 
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/ui] threw exception [Request processing failed; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.epam.hhsystem.model.vacancy.Vacancy#6]] with root cause 
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.epam.hhsystem.model.vacancy.Vacancy#6] 
    at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:697) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:296) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:241) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:109) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90) 
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:735) 
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:727) 
    at org.hibernate.engine.spi.CascadingAction$5.cascade(CascadingAction.java:258) 
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:388) 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:331) 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209) 
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:418) 
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:358) 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:334) 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209) 
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:166) 
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:132) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.cascadeOnUpdate(DefaultSaveOrUpdateEventListener.java:364) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:338) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:241) 
    at org.hibernate.event.internal.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:55) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90) 
    at org.hibernate.internal.SessionImpl.fireUpdate(SessionImpl.java:786) 
    at org.hibernate.internal.SessionImpl.update(SessionImpl.java:778) 
    at org.hibernate.internal.SessionImpl.update(SessionImpl.java:774) 
    at com.epam.hhsystem.jpa.EventDaoImpl.update(EventDaoImpl.java:45) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 
    at $Proxy38.update(Unknown Source) 
    at com.epam.hhsystem.services.EventService.update(EventService.java:24) 
    at com.epam.hhsystem.services.EventService$$FastClassByCGLIB$$3653e1b6.invoke(<generated>) 
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631) 
    at com.epam.hhsystem.services.EventService$$EnhancerByCGLIB$$8266fd26.update(<generated>) 
    at com.epam.hhsystem.web.controllers.EventMenuController.updateEvent(EventMenuController.java:164) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219) 
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) 
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) 
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745) 
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686) 
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) 
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925) 
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) 
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936) 
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:647) 
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) 
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) 
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) 
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) 
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) 
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) 
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009) 
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) 
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
    at java.lang.Thread.run(Thread.java:662) 

UPDATE 2

I noticed, that I have no problem if I write change mapping Vacancy in Event: 
@ManyToMany(/*cascade = CascadeType.ALL,*/ fetch = FetchType.EAGER)// I comment cascade 
    public Set<Vacancy> getVacancies() { 
     return vacancies; 
    } 

Почему? для лица кандидата и единственности этого отображения работы:

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    public Set<Candidate> getCandidates() { 
     return candidates; 
    } 

Если удалить связь между Event и Vacancy в Initally кода variant- он работает хорошо

Если удалить связь между Event и кандидатом в Initally кода variant- он DON 'T works

+1

Пожалуйста, размещайте полное исключение (спящий режим/весна), которое часто содержит некоторые полезные сведения о Exception, которые облегчают поиск ошибки. – Ralph

+0

Я обновил свой пост. –

ответ

0

Попробуйте объединить вакансии с текущей транзакцией, прежде чем использовать ее.

@PersistenceContext 
EntityManager entityManager; 

... 
public String updateEvent(Model model, 
     @Valid @ModelAttribute("existedEvent") Event event, 
     BindingResult result, 
     @ModelAttribute("linkedCandidates") Set<Candidate> candidates, 
     @ModelAttribute("linkedvacancies") Set<Vacancy> vacancies) { 

    if (result.hasErrors())... 

    ... 
    List<Vacancie> mergedVacancies = new ArrayList<>(); 
     if (vacancies != null) { 
     for(Vacancie v : vacancies) { 
      mergedVacancies.add(entityManager.merge(v)); 
     } 
    } 


    for (Vacancy vacancy : mergedVacancies) { 
     vacancy.getEvents().add(event); 
    } 
    ... 
    //Attention: mergedVacancies is not null like in the original code 
    event.setVacancies(mergedVacancies); 
    ... 
} 
4

Это происходит, если вы пытаетесь сохранить два объекта с одним и тем же идентификатором в одном сеансе.

Прежде всего этого не должно быть, попробуйте выяснить, почему это происходит и избежать этого. Если это оказывается требование в случае использования попробуйте

session.merge

Ура !!

+0

Я хочу найти причину возникших двух объектов –

+0

@ user2740224 - Я думаю, что вы уже сделали достаточно исследований самостоятельно, проблема в том же объекте событий существует как в кандидатах, так и в вакансиях, поэтому работающие параметры работают. Лучше всего было бы отдельно сохранить кандидатуру, вакансии и события. –