2016-12-09 5 views
0

私はSpring Data JPAを試していますが、ManyToOne関係の保存に問題があります。アプリケーションSpringデータJPAのManyToOne保存操作でorg.hibernate.PersistentObjectExceptionがスローされています

@SpringBootApplication 
public class Application { 

private static final Logger log = LoggerFactory.getLogger(Application.class); 

public static void main(String[] args) { 
    SpringApplication.run(Application.class); 
} 

@Bean 
public CommandLineRunner demo(CustomerRepository repository) { 
    return (args) -> { 



     Address address1 = new Address("07093", "Brooklyn", "129 67th st", null, "USA"); 
     Address address2 = new Address("03333", "Qeeens", "333 67th st", null, "USA"); 
     // save a couple of customers 
     Customer jack = new Customer("Jack", "Bauer"); 

     jack.setHomeAddress(address1); 
     repository.save(jack);     
     repository.save(new Customer("Chloe", "O'Brian",address1)); 

} 
} 

import org.springframework.data.jpa.repository.JpaRepository; 

public interface CustomerRepository extends JpaRepository<Customer, Long>  { 

List<Customer> findByLastName(String lastName); 
List<Customer> findByHomeAddress(Address address); 

} 

は、だから私は同じアドレスIと2人の顧客を保存しようとしました

@Entity 
public class Address { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    private String postalCode; 
    private String city; 
    private String line1; 
    private String line2; 
    private String country; 

    public Address() { 
    // TODO Auto-generated constructor stub 
    } 

    // getters and setter 
} 

CustomerRepository:

@Entity 
public class Customer { 

@Id 
@GeneratedValue(strategy=GenerationType.AUTO) 
private Long id; 
private String firstName; 
private String lastName; 


@ManyToOne(cascade=CascadeType.ALL) 
private Address homeAddress; 

protected Customer() {} 
// getters and setters ... 
} 

多くの顧客が同じアドレスを持つことができます次の例外が発生します。

Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: hello.Address; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: hello.Address 
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:299) ~[spring-orm-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) ~[spring-orm-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:491) ~[spring-orm-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) ~[spring-data-jpa-1.10.5.RELEASE.jar:na] 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] 
at com.sun.proxy.$Proxy60.save(Unknown Source) ~[na:na] 
at hello.Application.lambda$0(Application.java:35) [classes/:na] 
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) [spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE] 
... 6 common frames omitted 

この問題を解決するにはどうすればよいですか?あなたは完全なコードを参照してくださいthis git location

答えて

1

関係の反対側を追加して双方向にしてください。 Addressクラスで 、

@OneToMany(mappedBy = "homeAddress", fetch = FetchType.LAZY) 
private Set<Customer> customers 

EDIT:上記の提案は、問題を解決しません。 あなたの問題は私を不思議に思って、私は地元でそれをチェックしました。 これらの操作をそれぞれのトランザクションで実行すると、エンティティマネージャは最初の保存後に保存されたaddress1をデタッチします(リポジトリの操作ごとにエンティティマネージャ/セッションが閉じられます)。

エンティティマネージャを開いたままにする1つのトランザクション内ですべての操作をラップすると、メソッドが機能します(ロールバックロジックに応じて通常はサービスで実行されます) 以下のコードでテストしました。

package hello; 

    import javax.transaction.Transactional; 

    import org.springframework.beans.factory.annotation.Autowired; 
    import org.springframework.stereotype.Service; 

    @Service 
    public class CustomerService { 
     @Autowired 
     private CustomerRepository customerRepository; 

     @Transactional 
     public void store(){ 
      Address address1 = new Address("07093", "Brooklyn", "129 67th st", null, "USA"); 
      Address address2 = new Address("03333", "Qeeens", "333 67th st", null, "USA"); 
      // save a couple of customers 
      Customer jack = new Customer("Jack", "Bauer"); 

      jack.setHomeAddress(address1); 

      customerRepository.save(jack);     
      customerRepository.save(new Customer("Chloe", "O'Brian", address1)); 
     } 
    } 

また、私は

+0

同じ例外が発生しています。さらに、私は単方向性を保つことができる解決策を求めています。 –

+0

私の意見では、すべて正しいと思われます。いくつかのテストを実行するためのソースコードを提供できますか? –

+0

@simas_ch [this git location](https://github.com/suleimana/spring-data-jpa)の完全なコードを参照してください –

1

が最初addressRepositoryを使用して、あなたのアドレスを永続化し、それを参照のpom.xmlからnaryanaスターターを削除する必要がありました。

PSこの

Address address1 = new Address("07093", "Brooklyn", "129 67th st", null, "USA"); 
Address address2 = new Address("03333", "Qeeens", "333 67th st", null, "USA"); 
address1 = addressRepository.save(address1); 
address2 = addressRepository.save(address2); 

// save a couple of customers 
Customer jack = new Customer("Jack", "Bauer"); 
jack.setHomeAddress(address1); 
repository.save(jack);     
repository.save(new Customer("Chloe", "O'Brian",address1)); 

をお試しください:私はこれをテストしていませんが、これは動作するはずです。

+0

この解決法も同様に機能しましたが、私はcascade = CascadeType.MERGEを変更する必要がありました。 –

0

これは実際に私のために働いていた何のQ要約です:@Abdullah Wasiには示唆されているようにCustomerRepositoryとAddressRepositoryを使用して

1 - 。 CustomerRepositoryを使用して

@ManyToOne(cascade=CascadeType.MERGE) 
private Address homeAddress; 

2-および@isahの答えは1として@Transactionalとサービスから操作を実行します。この1は、限り、私はカスケード型としてカスケード= CascadeType.MERGEを持って働いていました。このオプションは、私がカスケード= CascadeTypeを持っている限り、同様に機能しました。ALLカスケード型として:私の操作はサービスクラスになってしまいますので、

@ManyToOne(cascade=CascadeType.MERGE) 
private Address homeAddress; 

サービス

package hello; 

import javax.transaction.Transactional; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Service; 

@Service 
public class CustomerService { 
    @Autowired 
    private CustomerRepository customerRepository; 

    @Transactional 
    public void store(){ 
     Address address1 = new Address("07093", "Brooklyn", "129 67th st", null, "USA"); 
     Address address2 = new Address("03333", "Qeeens", "333 67th st", null, "USA"); 
     // save a couple of customers 
     Customer jack = new Customer("Jack", "Bauer"); 

     jack.setHomeAddress(address1); 

     customerRepository.save(jack);     
     customerRepository.save(new Customer("Chloe", "O'Brian", address1)); 
    } 
} 

私は、より最適なソリューションとして@isah考えます。

関連する問題