Issue
I am new to Spring boot and I want to be able to delete the value of a forgein key if its entity is removed without deleting the whole entity linked to it; I explain in my case a single person who has an Account can be at the same time an Author and a Player, so if I delete an author I want to delete its refrence in Account table without deleting the whole account because this account can still point on player. I searched on the internet I found cascadetype but it will delete the whole account!
Thank you in advance! here is my entities
@Table(name = "account")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
@Column(name = "ID")
private Long id;
@ManyToOne
@JoinColumn(name = "Author")
private Author author;
@ManyToOne
@JoinColumn(name = "Player")
private Player player;
//attributs, getters & setters
}
@Table(name = "player")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Player implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
@Column(name = "ID")
private Long id;
//attributs, getters & setters
}
//ma.myapp.usersgestion.domain.Author
@Table(name = "author")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
@Column(name = "ID")
private Long id;
@OneToMany(mappedBy = "author")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@JsonIgnoreProperties(value = { "player", "author"}, allowSetters = true)
private Set<Account> accounts = new HashSet<>();
//attributs, getters & setters
}
UPDATE
Im using jhipster (spring boot with React) and h2 database (with disk-based persistence)
//AuthorResource.java
@RestController
@RequestMapping("/api")
@Transactional
public class AuthorResource {
private final Logger log = LoggerFactory.getLogger(AuthorResource.class);
private static final String ENTITY_NAME = "author";
@Value("${jhipster.clientApp.name}")
private String applicationName;
private final AuthorRepository authorRepository;
public AuthorResource(AuthorRepository authorRepository) {
this.authorRepository = authorRepository;
}
/**
* {@code DELETE /authors/:id} : delete the "id" author.
*
* @param id the id of the author to delete.
* @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
*/
@DeleteMapping("/authors/{id}")
public ResponseEntity<Void> deleteAuthor(@PathVariable Long id) {
log.debug("REST request to delete Author : {}", id);
authorRepository.deleteById(id);
return ResponseEntity
.noContent()
.headers(HeaderUtil.createEntityDeletionAlert(applicationName, true, ENTITY_NAME, id.toString()))
.build();
}
//...
}
//AuthorRepository
@SuppressWarnings("unused")
@Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {}
Solution
In your entity class author add the following:
@OneToMany(fetch = FetchType.LAZY, mappedBy = "author", cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST })
private Set<Account> accounts;
I've omitted the cascadetype CascadeType.REMOVE
from the list. This will prevent Account
from also being deleted when the related Author
entity is deleted.
EDIT:
If the above solution somehow doesn't work then you can also try adding @OnDelete(action = OnDeleteAction.NO_ACTION)
above the accounts
field.
@OnDelete
is a hibernate
specific annotation.
EDIT 2:
If none of the solutions provided above work then you can also consider making a javax.persistence.@PreRemove
annotated method that manually sets the author
field for each related Account
to null. You place this method inside the Author
class. A method that is annotated with @PreRemove
will always run before the entity is deleted. So for Author
you could use the following method to set all author_id fields to null.
@PreRemove
public void deleteAuthor(){
this.getAccounts().forEach(account -> account.setAuthor(null));
}
Answered By - Maurice
Answer Checked By - Terry (JavaFixing Volunteer)