JPA - deleteBy query not working, orphanRemoval=true not working - spring

I am unable to understand why JPA delete is not working. Here is my parent entity:
public class RoleEntity {
//...other attributes like name etc.
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
#JoinColumn(name = "role_id", referencedColumnName = "id", nullable = false, insertable = false, updatable = false)
private Set<RoleExtEntity> extensions;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "file_id", referencedColumnName = "id", nullable = false)
private FileEntity fileEntity;
}
RoleRepository:
#Repository
public interface RoleRepository extends JpaRepository<RoleEntity, Long> {
#Transactional
int deleteByFileEntityAndName(FileEntity fileEntity, String roleName);
}
I am trying to delete the RoleEntity using FileEntity and RoleName attributes. The delete query returns val = 1 however when I do a findBy again, it gives me the record instead of null (as I think the record should be deleted, both parent and child should be deleted).
FileEntity fileEntity = fileRepository.findByFolderId(id);
RoleEntity roleToBeDeleted = roleRepository.findByFileEntityAndName(fileEntity, roleName);
int val = roleRepository.deleteByFileEntityAndName(fileEntity, roleName);
RoleEntity doesroleExistEntity = roleRepository.findByFileEntityAndName(fileEntity, roleName);
I have tried out various solutions mentioned on this platform like by using:
orphanRemoval = true
#Transactional annotation
flush()
CascadeType.ALL
However, they don't seem to work. Can someone please let me know what I am doing incorrectly here? Thanks!
Update: The issue was that I was calling a wrong method from a persistence service in my code. That method was a readOnlyTransaction() which didn't allow me to do the delete so I had to use another method withTransaction() that solved my issue.

Other database query is logged when you call I think service method?
Yot call the jpa delete method.
JPA Method roleRepository.findByFileEntityAndName(fileEntity, roleName);
return something maybe try show check.

Related

JPA delete #ManyToOne Entity on EAGER collection

Very simple problem, but it looks like is impossible to achieve what I want
The entities:
public class C {
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "column")
private Set<B> cards = new HashSet<>();
}
public class B {
#ManyToOne(fetch = FetchType.EAGER, optional = false, cascade = CascadeType.DETACH)
#JsonIgnore
#JoinColumn(name="column_id", nullable = false)
private C column;
}
#Repository
public interface BRepository extends JpaRepository<B, Long> {
}
I want to delete the B entity without use the C Repository.
if I do something like:
final C column = columnService.create(board, new C(board, "column name", 1)); //works
final B card = cardService.create(column, new B(column, "card name", 2)); //works
bRepository.delete(card); //NOTHING HAPPENS
Absolutely nothing happens on delete query, no log, data isn't removed from DB, nothing.... doesn't matter if I'm within or out a #transaction.
WHAT I'VE TRIED:
1 - if i change Set cards to FetchType.LAZY, the delete works, [but i really wanted it to be eager]
2 - if create a custom query on repository like:
#Modifying
#Query("DELETE FROM Card c where c.id = :id")
public void deleteById(#Param("id") long id);
then the delete works BUT, I've EntityListeners for this entity, and as per JPA documentation it wont work on custom query... so i need this component working
Is there a way to delete the ONE side of relationship with EAGER fetch without custom query and without loading the other side of relationship?

Spring JPA: How to remove OneToOne related entities when master entity is removed?

First of all, thank you for interest in this question.
Here is the issue I am having with my relations.
I have a master entity which is #OneToOne referenced to 2 different tables. But the master entity has no references from those two tables.
#SQLDelete(sql = "UPDATE contract_reservation SET deleted = true WHERE id=?")
#Where(clause = "deleted=false")
public class ContractReservation extends AbsLongEntity {
#Column(nullable = false)
private String reservationNumber;
#Column(name = "date", nullable = false)
private LocalDate date;
#ManyToOne
private Company ownCompany;
Above is my master entity which is basis for two other entities. The code above is not complete, just a gist of what I have.
Below are the two other entities which has ContractReservation as their basis and #NotNull contract_reservation_id.
OriginalContract
#SQLDelete(sql = "UPDATE original_contract SET deleted = true WHERE id=?")
#Where(clause = "deleted=false")
public class OriginalContract extends AbsLongEntity {
#Column(nullable = false, unique = true)
private String contractNumber;
#OneToOne
#JoinColumn(nullable = false, unique = true)
private ContractReservation reservation;
private Boolean deleted;
FleetDashboard
#SQLDelete(sql = "UPDATE fleet_dashboard SET deleted = true WHERE id=?")
#Where(clause = "deleted=false")
public class FleetDashboard extends AbsLongEntity {
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne(cascade = {
CascadeType.REMOVE
})
#JoinColumn(nullable = false)
private ContractReservation contractReservation;
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne(cascade = {
CascadeType.REMOVE
})
private OriginalContract originalContract;
So far I have tried CascadeType.REMOVE, ALL. #OnDelete as seen in FleetDashboard entity but none of them worked so far. I also tried to write query but it is taking too long to respond.
What I want here is, when master entity(ContractReservation) is deleted, all related instances should also be deleted from related entities (OriginalContract, FleetDashboard).
For example, if I delete ContractReservation with id = 1, OriginalContract that has contract_reservation_id = 1 should also be deleted and so on. Main problem here seems #OneToOne relation and the fact that I have not referenced related entities in my master entity(ContractReservation).
Is there any way that can solve this issue without referencing related tables into master entity?
Thank you for your answers in advance.

JPARepository wont update entity on save

Very simple situation and JPA is killing my brain cells
#Entity
#Table(name = "food_entry")
#ublic class FoodEntry implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "product_name", nullable = false, unique = false, insertable = true, updatable = false, length = 256)
private String name;
#CreatedDate
#Column(name = "instant", updatable = false, unique = false, nullable = false, insertable = true)
private Instant instant = Instant.now();
#Min(value = 0, message = "calories must be positive")
#Column(name = "calories", updatable = false, insertable = true, nullable = false, unique = false)
private long calories;
}
#Transactional
public FoodEntry update(final FoodEntry newEntry, long id) {
final User loggedUser = SecurityUtils.getCurrentLoggedUser();
if (loggedUser == null || !loggedUser.getAuthorities().contains(Authority.ADMIN))
throw new AccessDeniedException("You dont have authorization to perform this action");
FoodEntry current = this.repository.findById(id).orElseThrow(() -> new NotFoundException("Not found FoodEntry with specified id: " + id));
current.setCalories(newEntry.getCalories());
current.setInstant(newEntry.getInstant());
current.setName(newEntry.getName());
try {
this.repository.save(current);
this.repository.flush();
return null;
}
catch (Exception e) {
throw e;
}
}
#Repository
public interface FoodRepository extends JpaRepository<FoodEntry, Long> {}
The code runs, the food entry is queried from database, but when i call save NOTHING HAPPENS,
the JPA simple returns the very same object i passed as parameter and no query runs on database... later get to that entity will return the outdated value
why? this is so simple what am i missing?
The very same code for CREATE works fine... but when i'm trying to update, the save method does nothing
The updatable = false attribute should be changed, JPA will not update the entities with attribute updatable as false so set it to true.
For more reference:
https://www.ibm.com/support/pages/jpa-entities-primary-key-automatically-generated-read-only-annotations
The problem is, that all of those attributes you want to update (calories, instant, name) have set their updatable=false.
Attributes with updatable=false can only be set until the first time you have called .save(..). After that, all those attributes won't be updated anymore, even if the transaction hasn't been flushed.
I found the answer, is something super stupid I going to post here in case someone is stuck with same problem:
https://github.com/spring-projects/spring-data-jpa/issues/1735
JPA wont update entities in case all fields are set to update false, it does not throw an error or exception or any kind of traceable log, it simple ignores the call
as the project had an early requirement of not editing i forgot to alter the entities after it changed
This problem came due to updatable=false, because whenever column is specified as updatable=false then it can not be updated through JPA.

How to write query spring boot

I have classe notification has attribut receiver with type User like this :
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "sender", referencedColumnName = "id")
#JsonIgnore
private User sender;
and user has attribut bed :
#ManyToOne
(fetch = FetchType.LAZY)
#JoinColumn(nullable = false, name = "idBed")
#JsonIgnore
private Bed idBed;
and bed has attribut room :
#ManyToOne
(fetch = FetchType.LAZY)
#JoinColumn(nullable = false, name = "idroom")
#JsonIgnore
private Room room;
and room has attribut :
#ManyToOne
(fetch = FetchType.LAZY)
#JoinColumn(nullable = false, name = "idCarePost")
#JsonIgnore
private CarePost carePost;
please need to read all this data please how can i do it ?
You can use JPARepository. It will give the CRUD features out of the box you don't need to write any query. For example, if you use the save(object) method in the service class it will save the object no need to write the insert query.
If you want to write your custom query in the repository you can write by using #Query("write your custom query", nativeQuery = true) annotation.
#Repository
public interface BlogRepository extends JpaRepository<Post, Integer> {
#Query(value = "select * from posts p where p.author like %:value%", nativeQuery = true)
List<Post> findByAuthor(String value);
}
The above example is a way to write a native query using JPARepository.
You have jpa repository method as below.
Find user by some attribute as below.
List<User> findByName();
Find user by bed as below.
List<User> findByBed( bed object);
Find user by with continue object.
List<User> findByBedRoomCarePostName(string
carePostName);

Spring Data, JPA #OneToMany Lazy fetch not working in Spring Boot

I have #OneToMany relationship between FabricRoll and FabricDefect.
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "fabric_roll_id", referencedColumnName = "fabric_roll_id")
private Set<FabricDefect> fabricDefects = new HashSet<>();
The problem is when I get FabricRoll by JpaRepository function
findAll()
the associate FabricDefect is also loaded.
I want to load only FabricRoll and FabricDefect should load when calling the function getFabricDefect()
FabricRollServiceImpl class
#Component
public class FabricRollServiceImpl implements IFabricRollService{
#Autowired
FabricRollRepository fabricRollRepository;
#Transactional(propagation = Propagation.REQUIRED)
#Override
public List<FabricRoll> getAllFabricRoll() {
FabricRoll fabricRoll1 = new FabricRoll();
fabricRoll1.setBatchNo("34344");
fabricRoll1.setLotNo("425");
fabricRoll1.setPoNo("42");
fabricRoll1.setRollLength(2343);
fabricRoll1.setRollNo("356");
fabricRoll1.setRollWidth(60);
fabricRoll1.setStyleNo("354");
FabricDefect fabricDefect = new FabricDefect();
fabricDefect.setDefectNote("note");
fabricDefect.setDefectPoint(3);
fabricDefect.setSegment(3);
fabricDefect.setYard(42);
Set<FabricDefect> fabricDefects = new HashSet<>();
fabricDefects.add(fabricDefect);
fabricRoll1.setFabricDefects(fabricDefects);
addFabricRoll(fabricRoll1);
FabricRoll fabricRoll = null;
return fabricRollRepository.findAll();
}
#Override
public void addFabricRoll(FabricRoll fabricRoll) {
fabricRollRepository.save(fabricRoll);
}
}
Break point:
Console:
It seems to be a debugging artifact.
At debugging time, because the transaction is still open, the watched lazy loaded entity properties will be loaded at the breakpoint evaluation time.
To check the "production" behavior you should insert a em.detach statement just before the breakpoint or use logging (as suggested by Manza) and check em.getEntityManagerFactory().getPersistenceUnitUtil().isLoaded(fabricRoll1.fabricDefects()) returns false on the detached entity.
(remember to inject EntityManager for example by declaring #PersistenceContext private EntityManager em;)
You don't need to use #JoinColumn, and you don't need to instantiate fabricDefects
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<FabricDefect> fabricDefects ;
See more in this question.
FabricDefect class:
#ManyToOne
#JoinColumn(name = "fabric_roll_id")
private FabricRoll roll;
FabricRoll class:
#OneToMany(mappedBy = "roll")
private Set<FabricDefect> fabricDefects;
Collections are by default loaded lazily, JPA will query the db only when the method getFabricDefects will be called.
You can see it by yourself enabling logging.
I found solution in this tutorial.
You have to modify FabricRoll OneToMany map as below:
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "fabricRoll")
private Set<FabricDefect> fabricDefects;
FabricDefect ManyToOne as below (remember to remove fabric_roll_id field if you included it in your entity):
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "fabric_roll_id")
private FabricRoll fabricRoll;
And you don't need to add #Transactional(propagation = Propagation.REQUIRED) before getAllFabricRoll() function.

Resources