2017-10-15 12 views
0

私はjpaspring-dataを初めて使っていますので、私の知らないことを許してください。JPA ManyToManyマッピングの問題(同じエンティティを別のエンティティにマッピングすることはできません)

私は2つのエンティティを持っている、と私は多対多の関係でお互いにそれらをマッピングトラブルを抱えている:

部門:

@Entity 
@Table(name = "Department") 
public class Department { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private Integer   id; 

    @Column(name = "name") 
    private String   name; 

    @ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }) 
    @JoinTable(name = "department_week_days", joinColumns = @JoinColumn(name = "department_id"), inverseJoinColumns = @JoinColumn(name = "week_day_id")) 
    private List<WeekDay> weekDays; 

    public Department(String name) { 
     this.name = name; 
     weekDays = new ArrayList<WeekDay>(); 
    } 

    protected Department() { 
    } 

    public void addWeekDay(WeekDay day) { 
     weekDays.add(day); 
     day.getDepartments().add(this); 
    } 

    // omitted setters and getters 

} 

平日:

@Entity 
public class WeekDay { 

    public static enum WeekDays { 

     MO("Monday", 1), TU("Tuesday", 2), WE("Wednesday", 3), TH("Thursday ", 4), FR("Friday", 5), SA("Saturday", 6), SU("Sunday", 7); 

     private String name; 
     private int  dayNum; 

     private WeekDays(String name, int dayNum) { 
      this.name = name; 
      this.dayNum = dayNum; 
     } 

     public int asInt() { 
      return dayNum; 
     } 

     @Override 
     public String toString() { 
      return name; 
     } 
    } 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private Integer    id; 

    @Column(name = "name") 
    private String    name; 

    @Transient 
    private int     numericOrder; 

    @Embedded 
    private WorkingHours  workingHours; 

    @Column(name = "minimumEmployees") 
    private Integer    minimumEmployees; 

    @Column(name = "maximumEmployees") 
    private Integer    maximumEmployees; 

    @ManyToMany(mappedBy = "weekDays") 
    private List<Department> departments; 

    public WeekDay(WeekDays day, WorkingHours workingHours, Integer minimumEmployees, Integer maximumEmployees) { 

     this.name = day.toString(); 
     this.numericOrder = day.asInt(); 
     this.workingHours = workingHours; 
     this.minimumEmployees = minimumEmployees; 
     this.maximumEmployees = maximumEmployees; 

     departments = new ArrayList<Department>(); 

    } 

    protected WeekDay() { 
    } 

    // omitted setters and getters 

} 

私の問題は、私は同じWeekDayに追加することはできませんということである二つの異なるDepartmentの 例えば:

WeekDay day = WeekDayFactory.create(WeekDayFactory.SA, WeekDayFactory.DAY_SHORT, 1, 2); 

Department d1 = new Department("d1"); 
d1.addWeekDay(day); 
repository.save(d1); 

Department d2 = new Department("d2"); 
d2.addWeekDay(day); 
repository.save(d2); 

上記の文句を言わない私はd2理由にdayを追加してみましょうか?

私はそれが動作dayと同じ値を持つnewWeekDayを作成する場合:

WeekDay day = WeekDayFactory.create(WeekDayFactory.SA, WeekDayFactory.DAY_SHORT, 1, 2); 
WeekDay sameValuesAsDay = WeekDayFactory.create(WeekDayFactory.SA, WeekDayFactory.DAY_SHORT, 1, 2); 

Department d1 = new Department("d1"); 
d1.addWeekDay(day); 
repository.save(d1); 

Department d2 = new Department("d2"); 
d2.addWeekDay(sameValuesAsDay); 
repository.save(d2); 

明らかに、これは私だけ追加することができますので、ManyToManyマッピングの目的に反しWeekDayテーブル内の重複行を作成しますデータはそれぞれdepartmentテーブルに入っており、それぞれdepartmentです。

私が最初に言ったように、私はこれを正しく行う方法について本当の考えを持っていないので、私の無知を言い訳し、私の問題を解決するために正しい方向に向かわせてください。

EDIT

スタックトレース:

java.lang.IllegalStateException: Failed to execute CommandLineRunner 
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:735) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE] 
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:716) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE] 
    at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:703) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:304) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE] 
    at com.kendaya.holidaysplaning.HolidaysPlaningApplication.main(HolidaysPlaningApplication.java:21) [classes/:na] 
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.kendaya.holidaysplaning.entities.WeekDay; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.kendaya.holidaysplaning.entities.WeekDay 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:299) ~[spring-orm-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) ~[spring-orm-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:488) ~[spring-orm-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) ~[spring-data-jpa-1.11.7.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) ~[spring-data-commons-1.13.7.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at com.sun.proxy.$Proxy66.save(Unknown Source) ~[na:na] 
    at com.kendaya.holidaysplaning.HolidaysPlaningApplication.lambda$0(HolidaysPlaningApplication.java:39) [classes/:na] 
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:732) [spring-boot-1.5.7.RELEASE.jar:1.5.7.RELEASE] 
    ... 6 common frames omitted 
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.kendaya.holidaysplaning.entities.WeekDay 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:765) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:758) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:398) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:162) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:431) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:363) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:162) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:111) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:278) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:109) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91] 
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) ~[spring-orm-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at com.sun.proxy.$Proxy64.persist(Unknown Source) ~[na:na] 
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:508) ~[spring-data-jpa-1.11.7.RELEASE.jar:na] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504) ~[spring-data-commons-1.13.7.RELEASE.jar:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489) ~[spring-data-commons-1.13.7.RELEASE.jar:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) ~[spring-data-commons-1.13.7.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56) ~[spring-data-commons-1.13.7.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.11.RELEASE.jar:4.3.11.RELEASE] 
    ... 17 common frames omitted 
+1

「d2」に「day」を追加することはできません。 stacktraceもポストしてください。 – Ish

+0

@Ish私は自分の問題が私が間違っていたことは些細なものだったと思っていました。私はstacktraceを追加しました...それが助けて欲しいです –

答えて

2

でコードを置き換えます期待どおりに動作します。しかし、次のエラーメッセージによって引き起こさ

:org.hibernate.PersistentObjectException:永続化するために渡されたデタッチエンティティ:com.kendaya.holidaysplaning.entities.WeekDay

はあなたdayインスタンスが切り離されることを語っています。おそらく、最初のrepository.save()呼び出しは別のトランザクションで実行されるため、save()呼び出し後に永続コンテキストがクリアされます。どちらかが第二部門エンティティを永続化する前に、最初のsave呼び出しの後dayレコードを再読み込み、または

Department d2 = new Department("d2"); 
WeekDay day1 = repository.find(day.getId()); //!!! pseodocode 
d2.addWeekDay(day1); 
repository.save(d2); 
  • が同じでrepository.save()コールの両方を実行

    • :あなたはこの問題を解決するために2つのオプションがありますこの場合、dayインスタンスは引き続き管理されます。

  • +0

    多くのおかげで、私はそれを理解する必要があった! 問題は今解決されました: 'd1.addWeekDay(日); d2.addWeekDay(日); repository.save(Arrays.asList(d1、d2)); ' –

    +0

    ようこそ。 – ujulu

    0
    Department d1 = new Department("d1"); 
    d1.addWeekDay(day); 
    repository.save(d1); 
    
    Department d2 = new Department("d2"); 
    d2.addWeekDay(sameValuesAsDay); 
    repository.save(d2); 
    

    私の知る限り見ることができるように、マッピングが正しいこと、すべてがすべき

    Department d1 = new Department("d1"); 
    d1.addWeekDay(day); 
    d1 =repository.save(d1); 
    
    Department d2 = new Department("d2"); 
    d2.addWeekDay(sameValuesAsDay); 
    d2 =repository.save(d2); 
    
    -1

    私はこの質問の受け入れられた答え、Detached entity passed to persist errorは根本的な原因を理解するのに役立つと思います。つまり、hibernateのsaveメソッドは一時オブジェクト(new演算子で作成されたオブジェクト)のみを受け入れます。 saveを使用してオブジェクトを永続化すると、そのオブジェクトは休止状態のセッション(ケースの日オブジェクト)でなくなり、エラーがスローされます。 saveOrUpdateメソッドを使用するか、またはujuluで提案された方法で試してみて、その日のオブジェクトを取り出してから保存してください。

    関連する問題