I would like to make complex validations when save or update an Entity. For example I'd like to check is one of the entity's property is unique, but trough complex conditions I can't declare in unique constraints.
I use @PrePersist for new entities, and @Pre/PostUpdate for existing ones. @PrePersist works well in all cases, but different errors occurred while updating existing entities. If I inject my CRUD service into listener, and check is there any existing records based on property value I get stack overflow exception - I think because every time I call CRUD service find method Hibernate tries to update the entity before run query, and the causes SO-. It is not a good practice to user CRUD service in EntityListener?
The other problem I don't know how to solve, if value cannot be persisted, I'd like to throw custom exception to inform the frontend about it. If I call saveAndFlush() just my exception is thrown. But If I use just save() a TransactionSystemException is also thrown after my custom exception and that TransactionSystemException will be populated to frontend instead of my exception.
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
How can I prevent RollbackException? Is it a good idea at all to check these restrictions in EntityListener? My goal is to implement a layer where these restrictions automatically validated.
You should probably use database that has support for this then because you will have a hard time getting this right and fast without that. PostgreSQL allows you to specify partial unique indexes, which essentially are unique constraints for a subset of the data. You can do e.g.
create unique index abc on tbl (tenant_id, some_code) where deleted = falseIf this doesn't work for you, you will probably have to use the SERIALIZABLE isolation level to ensure correctness, or use some kind of global lock.