Spring Data JPA Deleteby Query Not Working

Spring data jpa deleteBy query not working

Is the delete not working or not working as how you'd expect? Typically an entity has to be managed before it can be deleted, so a JPA provider (hibernate in your case) will load (the query you see) the entity first, then issue the delete.

If you're only seeing the query, but no corresponding delete, then some possibilities are:

  1. there's nothing to delete, make sure the record is there in the db
  2. the delete needs to be part of a transaction. I believe the Spring data CRUD ops are transactional by default, if not just make sure whatever is calling deleteByEmailAddress is transactional

Note: you can avoid the select when removing an entity using a modifying query delete, example below:

// NOTE: you have return void
@Modifying
@Transactional
@Query(value="delete from Contact c where c.emailAddress = ?1")
void deleteByEmailAddress(String emailAddress)

Spring Data problem - derived delete doesn't work

tl;dr

It's all in the reference documentation. That's the way JPA works. (Me rubbing hands washing.)

Details

The two methods do two different things: Long deleteBySystemId(String systemId); loads the entity by the given constraints and ends up issuing EntityManager.delete(…) which the persistence provider is about to delay until transaction commits. I.e. code following that call is not guaranteed that the changes have already been synced to the database. That in turn is due to JPA allowing its implementations to actually do just that. Unfortunately that's nothing Spring Data can fix on top of that. (More rubbing, more washing, plus a bit of soap.)

The reference documentation justifies that behavior with the need for the EntityManager (again a JPA abstraction, not something Spring Data has anything to do with) to trigger lifecycle events like @PreDelete etc. which users expect to fire.

The second method declaring a modifying query manually is declaring a query to be executed in the database, which means that entity lifecycles do not fire as the entities do not get materialized upfront.

However the Spring developers were quick to wash their hands and write it off as a Hibernate problem so no solution or explanation to be found there.

There's detailed explanation why it works the way it works in the comments to the ticket. There are solutions provided even. Workarounds and suggestions to bring this up with the part of the stack that has control over this behavior. (Shuts faucet, reaches for a towel.)

Spring data JPA expression using deleteBy

This article show how to return deleted records: Spring Data JPA – Derived Delete Methods

And try maybe this code:

List<Student> deleteAllByStudentNameIsNullOrStudentNameAndStudentIdIn(String studentName, List<Integer> studentIds);

But can't be sure that will be work because I don't know your Student's model structure.

Spring Data JPA : Repository DeleteById method not working

The "problem" is your mapping. Your collection is retrieved eagerly. Now why would that be an issue? The deleteById in Spring Data JPA first does a findById which in your case, loads the associated entities eagerly.

Now entity is attempting to be deleted but due to it being still attached and referenced by another entity it would be persisted again, hence the delete is canceled.

Possible solutions:

  • Delete using a query and write your own query method for this
  • Mark either side of the association lazy

Example:

@Entity
public class Ability {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String color;
private String image;

@ManyToOne(
fetch = FetchType.LAZY
)
private Subject subject;

@OneToMany(
mappedBy = "ability",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private Set<Technology> technologies;
}

@Repository
public interface AbilityRepository extends CrudRepository<Ability, Integer> {
}

Controller:

abilityRepository.deleteById(abilityId);

Spring Data: "delete by" is supported?

Deprecated answer (Spring Data JPA <=1.6.x):

@Modifying annotation to the rescue. You will need to provide your custom SQL behaviour though.

public interface UserRepository extends JpaRepository<User, Long> {
@Modifying
@Query("delete from User u where u.firstName = ?1")
void deleteUsersByFirstName(String firstName);
}

Update:

In modern versions of Spring Data JPA (>=1.7.x) query derivation for delete, remove and count operations is accessible.

public interface UserRepository extends CrudRepository<User, Long> {

Long countByFirstName(String firstName);

Long deleteByFirstName(String firstName);

List<User> removeByFirstName(String firstName);

}

Spring Data JPA: deleteById does not delete record from database but derived delete method does

I found the root cause. There was another entity having a reference to Inbox like this:

@OneToMany(mappedBy = "inbox", cascade = ALL, fetch = FetchType.EAGER)
private Set<Inbox> inbox = new HashSet<>();

The FetchType.EAGER in combination with the cascade caused the problem, i.e. as soon as the Inbox was deleted, this reference caused the Inbox to get "re-persisted". Setting FetchType.LAZY resolved the problem.



Related Topics



Leave a reply



Submit