Reputation: 3499
I'm using Spring jpa and mysql, I'm having problems with deleting entities, how to do it in the best way?
My Entity user :
@ManyToMany(cascade = CascadeType.REMOVE)
@JoinTable(name = "users_tasks",
joinColumns = {@JoinColumn(name = "user_id")},
inverseJoinColumns = {@JoinColumn(name = "task_id")})
private List<Task> tasks;
My Entity task :
@ManyToMany(fetch=FetchType.LAZY, mappedBy = "tasks")
private List<User> users = new ArrayList<>();
delete user in userServiceImpl (I'm not sure if this is correct but it works):
user.setTasks(Collections.emptyList());
userRepository.save(user);
userRepository.delete(user);
delete task in taskServiceImpl (it does not work):
task.setUsers(Collections.emptyList());
taskRepository.save(task);
taskRepository.delete(task);
exception:
java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`testdb`.`users_tasks`, CONSTRAINT `FK7todmyl52eiddpi6hc2nfgvbs` FOREIGN KEY (`task_id`) REFERENCES `tasks` (`task_id`))
my jpa config:
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(
env.getRequiredProperty("database.driver");
dataSource.setUrl(env.getRequiredProperty("database.url"));
dataSource.setUsername(env.getRequiredProperty("database.password"));
dataSource.setPassword(env.getRequiredProperty("database.username"));
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource());
factory.setPackagesToScan("com.taskmanager");
factory.setJpaVendorAdapter(vendorAdapter);
factory.setJpaProperties(additionalProperties());
return factory;
}
@Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
@Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
initializer.setDatabasePopulator(databasePopulator());
return initializer;
}
private Properties additionalProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.hbm2ddl.auto", env.getRequiredProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.enable_lazy_load_no_trans",
env.getRequiredProperty("hibernate.enable_lazy_load_no_trans"));
return properties;
}
private DatabasePopulator databasePopulator() {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.addScript(dataScript);
return populator;
}
Help me find the best workaround for removal, are my settings correctly spelled? Thank you
Upvotes: 0
Views: 1209
Reputation: 4158
In your example, the table User
is the owner of the relationship, that's why when updating a user's tasks Hibernate deletes the list of tasks.
One work around to this is to make both entities as the owners of the relationship by setting a join table on the task entity :
@ManyToMany(fetch=FetchType.LAZY)
@JoinTable(name = "users_tasks",
joinColumns = {@JoinColumn(name = "task_id")},
inverseJoinColumns = {@JoinColumn(name = "user_id")})
private List<User> users = new ArrayList<>();
Please notice that the inverse cloumns are reversed ,the mapped by is removed and the table name is the same.
Another workaround ,which is worth to mention, is to manage the cascade directly on your Database by altering the users_tasks
fks using ON DELETE CASCADE
Upvotes: 1