我正在尝试持久化一个与其他已持久化对象具有多对多关系的对象。
下面是我的持久化对象(它们已经持久化在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
类,它接收一个产品名称数组,使用该名称查找产品并将它们放入reservation对象中。
@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);
}
这是我的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();
}
@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;
}
}
下面是完整的堆栈跟踪:
严重:路径为[/web]的上下文中servlet [dispatcher]的Servlet.service()引发了异常错误[请求处理失败;嵌套的异常错误是org.springframework.dao。无效数据访问应用程序使用异常错误:传递到持久化的分离实体:网站.预订.服务.域名.产品;嵌套的异常是组织。传递到持久化的分离实体:出现根原因为org. hib的持久对象异常:传递到持久化的分离实体:如果您有任何问题,请联系我们。如果您有问题,请联系我们。
7条答案
按热度按时间0wi1tuuw1#
我遇到了同样的问题,通过删除X1 M0 N1 X解决了它。
在本例中,您使用
CascadeType.ALL
,根据文档,这相当于也使用PERSIST:定义传播到关联实体的可级联操作集。值cascade=ALL等效于cascade={PERSIST,MERGE,REMOVE,REFRESH,DETACH}。
这意味着,当您尝试在
reservationDAO.save(reservation)
上保存预订时,它还将尝试保留关联的产品对象。但此对象未附加到此会话。因此出现错误。eeq64g8w2#
当保存预订时,Hibernate尝试持久化关联的产品时会出现异常。
但您从存储库中获取了产品,并且ID不为空。
有两个选项可解决您的问题:
1.删除保留的产品上的
(cascade = CascadeType.ALL)
1.或删除产品ID上的
@GeneratedValue(strategy=GenerationType.AUTO)
tyu7yeag3#
您需要确保在代码中正确维护关系的双方。
如下所示更新Reservation,然后将相应的方法添加到Product。
在产品中:
现在你应该能够调用保存产品或预订和一切都应该工作的预期,所以你会很高兴。
8tntrjer4#
移除@ManytoMany关系中的@ CascadeType.ALL,这对我很有效。
9jyewag05#
entityManager.merge()
是一个很好的选项。它将合并会话中分离的对象。不需要更改任何cascadeType。bis0qfac6#
我感觉您的注解有一点不正确。虽然不太正确,但请查看示例7.24,看看它是否与您的注解匹配。忽略
Collection
数据类型,因为使用Set
应该不会有任何问题。我注意到您的Product
集合中缺少了cascade=CascadeType.ALL
,但我不知道这是不是问题所在。实际的异常是说,当它试图保存
Product
的集合时,你的Product
对象实际上还没有被保存。这就是为什么我认为这是你的注解的问题。试试看,如果你有什么进展就告诉我。
puruo6ea7#
我也遇到过类似的问题。我用
CascadeType.MERGE
替换了CascadeType.ALL
,它对我很有效。Map可以是
ManyToMany
或OneToOne
。