spring数据jpa和hibernate分离的实体传递给ManyToMany关系持久 [英] spring data jpa and hibernate detached entity passed to persist on ManyToMany relationship

查看:115
本文介绍了spring数据jpa和hibernate分离的实体传递给ManyToMany关系持久的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



下面是我的持久对象(它们已经存在于db中,这是一个MySQL):
Product

  @Entity 
@Table(name =PRODUCT)
public class Product {

private int productId;
私人字符串productName;
私人套餐<预订> 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(){
返回保留;
}
public void setReservations(Set< Reservation> reservations){
this.reservations = reservations;


$ / code $ / pre

这里是我没有持续的对象,我正在尝试创建

  @Entity 
@Table(name =RESERVATION)
public class Reservation {

private int reservationId;

私人套餐<产品> 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 = {@JoinColumn(name =productId,
nullable = false,updatable = false)})
public Set< Product> getProducts(){
返回产品;
}

public void setProducts(Set< Product> product){
this.products = products;




$ b

这是我的ReservationService类,它接收一个数组产品名称,使用名称查看产品并将它们放入预留对象中。

  @Service 
public class ReservationServiceImpl实现ReservationService {

@Autowired
私有ProductDAO productDAO;
@Autowired
私人ReservationDAO预订DAO;

@Transactional
public void createReservation(String [] productNames){

Set< Product> products = new HashSet< Product>(); (字符串productName:productNames){
Product pi = productDAO.findByProductName(productName);

products.add(pi);
}
预约预订=新预约();
reservation.setProducts(products);
reservationDAO.save(预订); --->在这里,我将分离的实体传递给persist
}
}

这里是我的ProductDAO接口:

  public interface ProductDAO扩展了JpaRepository< Product,Integer> {

public Product findByProductName(String productName);

$ / code>

这是我的spring配置文件:

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

$ b $Bean
public PlatformTransactionManager transactionManager(){
EntityManagerFactory factory = entityManagerFactory()。getObject();
返回新的JpaTransactionManager(工厂);


$Be $ b $ 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)));

属性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(新InstrumentationLoadTimeWeaver());
退货工厂;


$Be
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));
返回dataSource;


$ / code>

以下是完整的堆栈跟踪:

  SEVERE:Servlet.service()用于与路径[/ web]上下文中的servlet [dispatcher]抛出异常[Request processing failed; 
嵌套异常是org.springframework.dao.InvalidDataAccessApiUsageException:传递给persist的分离实体:com.reservation.service.domain.Product;
嵌套的异常是org.hibernate.PersistentObjectException:将根据原因传递给persist:com.reservation.service.domain.Product的分离实体
org.hibernate.PersistentObjectException:传递给persist:com的分离实体。 reservation.service.domain.Product
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)


解决方案

我遇到同样的问题,通过移除 cascade = CascadeType.PERSIST 来解决它。



根据文档,您可以使用 CascadeType.ALL ,这相当于也使用了PERSIST。


定义传播到关联实体的一组级联操作。值cascade = ALL等同于cascade = {PERSIST,MERGE,REMOVE,REFRESH,DETACH}。

这意味着当您尝试要保存 reservationDAO.save(保留)上的保留,它也会尝试保留关联的Product对象。但是这个对象没有附加到这个会话中。所以发生错误。


I am trying to persist an object that has a manytomany relationship with other objects already persisted.

Here is my persisted object (they are already persisted in the db, which is a mysql): Product

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

Here is my no persisted object, which I am trying to create

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

This is my ReservationService class, which receives an array of products names, look the products using the name and put them into the reservation object.

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

Here is my ProductDAO interface:

public interface ProductDAO extends JpaRepository<Product, Integer> {

    public Product findByProductName(String productName);
}

This is my spring config file:

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

Here is the full stack trace:

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)

解决方案

I had the same problem and solved it by removing the cascade = CascadeType.PERSIST.

In your case you use CascadeType.ALL, which is equivalent to also using the PERSIST, according to the documentation:

Defines the set of cascadable operations that are propagated to the associated entity. The value cascade=ALL is equivalent to cascade={PERSIST, MERGE, REMOVE, REFRESH, DETACH}.

It means when you try to save the reservation on reservationDAO.save(reservation) it will also try to persist the associated Product object. But this object is not attached to this session. So the error occur.

这篇关于spring数据jpa和hibernate分离的实体传递给ManyToMany关系持久的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆