[SPRING] Spring 데이터 jpa와 최대 절전 모드로 분리 된 엔티티가 ManyToMany 관계에서 지속되도록 전달됨
SPRINGSpring 데이터 jpa와 최대 절전 모드로 분리 된 엔티티가 ManyToMany 관계에서 지속되도록 전달됨
이미 유지 된 다른 객체와 수 많은 관계가있는 객체를 유지하려고합니다.
여기에 내 영속 객체가 있습니다 (그들은 이미 db로 유지되어 있습니다, 이것은 mysql입니다) : 생성물
@Entity
@Table(name="PRODUCT")
public class Product {
private int productId;
private String productName;
private Set<Reservation> reservations = new HashSet<Reservation>(0);
@Id @GeneratedValue(strategy=GenerationType.AUTO)
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
@Column(nullable = false)
public String getProduct() {
return product;
}
public void setProduct(String product) {
this.product = product;
}
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "products")
public Set<Reservation> getReservations() {
return reservations;
}
public void setReservations(Set<Reservation> reservations) {
this.reservations = reservations;
}
}
여기에 내 영속적 인 대상이 없습니다.
@Entity
@Table(name = "RESERVATION")
public class Reservation {
private int reservationId;
private Set<Product> products = new HashSet<Product>(0);
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getReservationId() {
return reservationId;
}
public void setReservationId(int reservationId) {
this.reservationId = reservationId;
}
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "product_reservation", joinColumns = { @JoinColumn(name = "reservationId", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "productId",
nullable = false, updatable = false) })
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
}
이 클래스는 제품 이름 배열을 받고 이름을 사용하여 제품을 찾고 예약 객체에 넣는 ReservationService 클래스입니다.
@Service
public class ReservationServiceImpl implements ReservationService {
@Autowired
private ProductDAO productDAO;
@Autowired
private ReservationDAO reservationDAO;
@Transactional
public void createReservation(String[] productNames) {
Set<Product> products = new HashSet<Product>();
for (String productName : productNames) {
Product pi = productDAO.findByProductName(productName);
products.add(pi);
}
Reservation reservation = new Reservation();
reservation.setProducts(products);
reservationDAO.save(reservation); ---> Here I am getting detached entity passed to persist
}
}
다음은 내 ProductDAO 인터페이스입니다.
public interface ProductDAO extends JpaRepository<Product, Integer> {
public Product findByProductName(String productName);
}
이것은 나의 봄 설정 파일이다.
@Configuration
@PropertySource(value = { "classpath:base.properties" })
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.reservation.dao")
public class RepositoryConfig {
@Autowired
private Environment env;
@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public PlatformTransactionManager transactionManager() {
EntityManagerFactory factory = entityManagerFactory().getObject();
return new JpaTransactionManager(factory);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(Boolean.valueOf(env
.getProperty("hibernate.generate.ddl")));
vendorAdapter.setShowSql(Boolean.valueOf(env
.getProperty("hibernate.show_sql")));
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.hbm2ddl.auto",
env.getProperty("hibernate.hbm2ddl.auto"));
jpaProperties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource());
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.reservation.service.domain");
factory.setJpaProperties(jpaProperties);
factory.afterPropertiesSet();
factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
return factory;
}
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
}
다음은 전체 스택 추적입니다.
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/web] threw exception [Request processing failed;
nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.reservation.service.domain.Product;
nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.reservation.service.domain.Product] with root cause
org.hibernate.PersistentObjectException: detached entity passed to persist: com.reservation.service.domain.Product
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)
해결법
-
==============================
1.나는 같은 문제를 가지고 계단식 = CascadeType.PERSIST를 제거하여 해결했다.
나는 같은 문제를 가지고 계단식 = CascadeType.PERSIST를 제거하여 해결했다.
귀하의 경우에는 문서에 따라 PERSIST를 사용하는 것과 동일한 CascadeType.ALL을 사용하십시오.
이는 예약 DAO.save (예약)에 예약을 저장하려고하면 연결된 Product 객체를 유지하려고 시도한다는 것을 의미합니다. 그러나이 객체는이 세션에 첨부되지 않습니다. 그래서 오류가 발생합니다.
-
==============================
2.예외는 예약을 저장할 때 관련 제품을 지속 시키려고 최대 절전 모드로 제공됩니다. 제품의 ID가 @GeneratedValue (strategy = GenerationType.AUTO)로 주석되어 있기 때문에 ID가없는 경우에만 제품을 유지할 수 있습니다.
예외는 예약을 저장할 때 관련 제품을 지속 시키려고 최대 절전 모드로 제공됩니다. 제품의 ID가 @GeneratedValue (strategy = GenerationType.AUTO)로 주석되어 있기 때문에 ID가없는 경우에만 제품을 유지할 수 있습니다.
하지만 저장소에서 제품을 가져 왔고 ID는 null이 아닙니다.
문제를 해결할 수있는 2 가지 옵션이 있습니다.
-
==============================
3.관계의 양면이 코드에서 올바르게 유지되도록해야합니다.
관계의 양면이 코드에서 올바르게 유지되도록해야합니다.
아래와 같이 예약을 업데이트 한 다음 해당 메소드를 Product에 추가하십시오.
@Entity @Table(name = "RESERVATION") public class Reservation { private int reservationId; private Set<Product> products = new HashSet<Product>(0); @Id @GeneratedValue(strategy = GenerationType.AUTO) public int getReservationId() { return reservationId; } public void setReservationId(int reservationId) { this.reservationId = reservationId; } @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinTable(name = "product_reservation", joinColumns = { @JoinColumn(name = "reservationId", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "productId", nullable = false, updatable = false) }) public Set<Product> getProducts() { //force clients through our add and remove methods return Collections.unmodifiableSet(products); } public void addProduct(Product product){ //avoid circular calls : assumes equals and hashcode implemented if(! products.contains(product){ products.add(product); //add method to Product : sets 'other side' of association product.addReservation(this); } } public void removeProduct(Product product){ //avoid circular calls: assumes equals and hashcode implemented: if(product.contains(product){ products.remove(product); //add method to Product: set 'other side' of association: product.removeReservation(this); } } }
그리고 제품 :
public void addReservation(Reservation reservation){ //assumes equals and hashcode implemented: avoid circular calls if(! reservations.contains(reservation){ reservations.add(reservation); //add method to Product : sets 'other side' of association reservation.addProduct(this); } } public void removeReservation(Reservation reservation){ //assumes equals and hashcode implemented: avoid circular calls if(! reservations.contains(reservation){ reservations.remove(reservation); //add method to Product : sets 'other side' of association reservation.reomveProduct(this); } }
이제 Product 또는 Reservation에서 save를 호출 할 수 있어야하며 모든 것이 예상대로 작동해야합니다.
-
==============================
4.귀하의 특수 효과가 약간 잘못되었다는 느낌이 들었습니다. 많은 예제가 아니라 예제 7.24를보고 주석과 일치하는지 확인하십시오. 세트를 사용하는 데 문제가 없어야하므로 Collection 데이터 유형을 무시하십시오. 제품 카탈로그에 Cascade = CascadeType.ALL이 누락되어 있음을 확인했지만 문제가있는 경우 해결할 수 없습니다.
귀하의 특수 효과가 약간 잘못되었다는 느낌이 들었습니다. 많은 예제가 아니라 예제 7.24를보고 주석과 일치하는지 확인하십시오. 세트를 사용하는 데 문제가 없어야하므로 Collection 데이터 유형을 무시하십시오. 제품 카탈로그에 Cascade = CascadeType.ALL이 누락되어 있음을 확인했지만 문제가있는 경우 해결할 수 없습니다.
실제 예외가 말하는 것은 제품의 컬렉션을 저장할 때 Product 객체가 실제로 저장되지 않았다는 것입니다. 그래서 내가 주석에 문제가 있다고 생각합니다.
그것을 밖으로 시도하고 어디서나하면 알려주세요.
-
==============================
5.entityManager.merge ()가 좋은 옵션입니다. 분리 된 객체를 세션에서 병합합니다. 캐스케이드 유형을 변경할 필요가 없습니다.
entityManager.merge ()가 좋은 옵션입니다. 분리 된 객체를 세션에서 병합합니다. 캐스케이드 유형을 변경할 필요가 없습니다.
from https://stackoverflow.com/questions/23645091/spring-data-jpa-and-hibernate-detached-entity-passed-to-persist-on-manytomany-re by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] @TestPropertySource 및 @PropertySource가 JUnit에서 작동하지 않습니다. (0) | 2018.12.20 |
---|---|
[SPRING] Spring에서 객체 목록의 유효성 검사 (0) | 2018.12.20 |
[SPRING] Spring v3 'mvc : resources'요소에 대한 선언을 찾을 수 없습니다. (0) | 2018.12.20 |
[SPRING] Autowired 환경이 null입니다. (0) | 2018.12.20 |
[SPRING] 페이스 북 토큰을 인증에 사용하는 Stateless REST Endpoint 용 스프링 소셜 인증 필터 (0) | 2018.12.20 |