How to create a dyncamic update query with JPQL? - spring

I have to update an entity by ensuring it's already there in the database(Primary key is not auto generated).Therefor I cannot use only thesave() method to overcome this issue.There must be a way to ensure that the inserted primary key is already existing.To overcome this issue I know I can follow several approaches like below.But I found creating my own update statement is the most optimal way to solve this problem.
So I need to create a dynamic update query with JPQL . I know you will say why don't you use a method like getOne() or findOne() and set the necessary fields for the entity and save() .But I think using a findOne() or getOne() leads to an additional db hit to fetch the relevant entities .So I can omit the fetch by going with a custom update query.
I guess using #DynamicUpdate also won't resolve the problem ,because as far as I know it's also fetch the entity from the database to compare the changed fields during an updation.
So both of the above mentioned approaches leads to an additional db hit.
So is there a way to write a custom jpql query to update only the fields which are not null.
I have achieved similar kind of behaviour with fetching by writing dynamic where clauses.But didn't find a way to do the same with update.
Ex for dynamic select with JPQL:
SELECT d FROM TAndC d WHERE (:termStatus is null or d.termStatus= :termStatus ) AND (:termType is null or d.termType=:termType) AND (:termVersion is null or d.termVersion=:termVersion)"

#Modifying
#Query("update entity e set e.obj1=:obj1 and e.obj2=:obj2 where e.id=:id")
public void updateCustom(String obj1, String obj2, String id);
I wrote a pseudo code.
It is possible with spring data.
Also you can use jpa entity manager to create update statement and dynamic query programatically

Related

Spring data update just one entity field

i’m new to spring when i try to update just one field of an entity I noticed in logs that hibernate perform two queries, before update it does a SELECT of all fields. Is that ok? Why does Hibernate perform that SELECT? How can i update a field with just one UPDATE query? Additionally when I tried to update a single title in an entity that has another nested entity i end up with a bunch of SELECT. I think it’s not good for performance or I’m wrong?
Something s = somethingRepository.findById(id);
s.setField1(someData);
somethingRepository.save(s);
On the internet I found a solution to make custom query with #Modifying and #Query(“UPDATE …”) but in this way I need to make custom query for every single field. Is there a better solution?
As per the source code you have pasted in the question
Something s = somethingRepository.findById(id);
s.setField1(someData);
somethingRepository.save(s);
if the entity Something which you are asking does not exist in the hibernate first level cache, it will make one SELECT call.
and as you are updating field 1 value then it will make another update call.
It does not matter if you are using save or not because Hibernate dirty checks will ensure that all changes are updated.
otherwise you can use custom method with #Modifying with JPQL and named params. It is more readable than ?1,
#Modifying
#Query("UPDATE Something s SET s.field = :fieldValue WHERE s.id = :id")
void updateField(String fieldValue, UUID id);
Regarding that you are seeing multiple calls "when I tried to update a single title in an entity that has another nested entity". It depends on how you have created the relationship among entities. If you can share the entities and their relationship then only it can be answered accurately.
Because internally the repository.save() method does an upsert. If you go to the inner classes and check you will see that first, it will check whether the entity is present in the database then based on that it will perform add or update. If you don't want the SELECT query to run then you can use the native query offered by the JPA repository. You can do something like this:
#Modifying
#Transactional
#Query("UPDATE <tableName> SET <columnName> = ?1 WHERE <condition>" ,nativeQuery=true)
void updateSomething(String value);

Retrieve the deleted record spring JPA

I am working on a spring application.
We have a specific requirement where when we get a specific event, we want to look it up in the DB. If we find the record in the DB, then we delete it from DB, create another event using the details and trigger it.
Now my concern is:
I do not want to use two different calls, one to find the record and another to
delete the record.
I am looking for a way where we can delete the record using a custom
query and simultaneously fetch the deleted record.
This saves two differnet calls to DB, one for fetch and another for delete.
What I found on the internet so far:
We can use the custom query for deletion using the annotation called #Modifying. But this does not allow us to return the object as a whole. You can only return void or int from the methods that are annotated using #Modifying.
We have removeBy or deleteBy named queries provided by spring. but this also returns int only and not the complete record object that is being deleted.
I am specifically looking for something like:
#Transactional
FulfilmentAcknowledgement deleteByEntityIdAndItemIdAndFulfilmentIdAndType(#Param(value = "entityId") String entityId, #Param(value = "itemId") String itemId,
#Param(value = "fulfilmentId") Long fulfilmentId, #Param(value = "type") String type);
Is it possible to get the deleted record from DB and make the above call work?
I could not find a way to retrieve the actual object being deleted either by custom #Query or by named queries. The only method that returns the object being deleted is deleteById or removeById, but for that, we need the primary key of the record that is being deleted. It is not always possible to have that primary key with us.
So far, the best way that I found to do this was:
Fetch the record from DB using the custom query.
Delete the record from DB by calling deleteById. Although, you can now delete it using any method since we would not be requiring the object being returned by deleteById. I still chose deleteById because my DB is indexed on the primary key and it is faster to delete it using that.
We can use reactor or executor service to run the processes asynchronously and parallelly.

Spring JPA Derived query method groupBy

Hi I was building an app and was wondering on how I can convert this query into a derived query method without using the annotation #Query:
SELECT address, COUNT(*) address FROM `employee` GROUP BY address ORDER BY address DESC LIMIT 5
I have tried it here is how I did it
List<Employee> countByAddressGroupByAddressByOrderByAddressDescLimit5();
This throws the following error
Invalid derived query! No property groupByAddressBy found for type String! Traversed path: Employee.address.
I was wondering if what am I doing wrong here thank you in advance.
I don't think query derivation supports group by.
You can't.
Derived queries don't support GROUP BY.
Derived queries are intended only for simple queries, where the mapping between a normal method name that you might choose independently from Spring Data and the query needed for implementation is obvious.
For more complex cases like the one you describe other mechanisms are available, like annotated or named queries. Nobody wants to use a method name like countByAddressGroupByAddressByOrderByAddressDescLimit5 anyway.
As others said, derived queries do not support this. There might be other reasons besides simply not being a 'practical' solution.
AFAIK derived query methods are restricted to retrieving instances just for the entity type managed by the repository (you can retrieve MyEntity, Optional<MyEntity>, Collection<MyEntity>, etcetera) or projections that match the fields/columns used for the managed entity.
When you use 'Group By', you break with this resultset structure, you usually have to explicitly indicate which columns you want to retrieve or which operations you want to perform on the grouped columns (which would be impossible using just a method name).
TL;DR
You can't easily indicate the columns you want to include in a 'Grouped By' query result, so no, I don't think there is a way to use this technique with 'Group By'.

How to actualize entity in Spring JPA? Actualize or create new one?

I'm wondering what is best practice to update JPA entity in Spring project - update original entity or create new? I see these two approaches:
Use original - Actualize necessary fields in original entity and save this updated entity back to the repository.
Use copy - manually create new instance of entity, set all field from original entity (+ updated fields) into new entity and save the entity back to the repository.
What approach do you use / is recommended? And why?
When it comes to updating, the standard way would be to retrieve the entity reference(read below) and make changes within a transactional method:
private JpaRepository repo;
#Transactional(readOnly = false)
public void performChanges(Integer id){
Entity e = repo.getOne(id);
// alter the entity object
}
Few things regarding the example:
You would want to use the getOne method of JpaRepository as much as possible as it is in general faster than the findOne of the CrudRepository. The only trick is that you have to be sure that entity actually exists in the database with the given id. Otherwise you would get an exception. This does not occur regarding the findOne method so you would need to make that decision regarding each transactional method which alters a single entity within your application.
You do not need to trigger any persist or save methods on the EntityManager as the changes will be automatically flushed when the transaction is commited.. and that is on method return.
Regarding your second option, I dont think thats much of a use as you would need to get the data using above method anyway. If you intend to use that entity outside of the transaction, then again you could use the one retrieved from the exmaple above and then perform merge once it is again needed within the transactional context and thus Persistence Provider.
Getting an entity and then just updating that entity is the easiest way to do that. Also this is faster than a creation of a copy since EntityManager manages an entity and know that managed entity already exists in DB (so no need to execute additional query).
Anyway, there is third and the fastest approach: using executeUpdate on Query object.
entityManager
.createQuery("update EntityName set fieldName = :fieldName where id = :id")
.setParameter("fieldName", "test")
.setParameter("id", id)
.executeUpdate();
It is faster due to bypassing the persistent context

laravel : insert or update record when exists using DB facade

is there any method for inserting new record or update when record exists in database using DB facade ?
Note: there is no model but only a controller , so using model related methods is impossible.my question is regards to query builder
The most straightforward approach is to look into your database's syntax for upserting. It will be different depending on the database and the specific situation, and may require defining a UNIQUE key of some kind.
Here is an example for MySQL:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
By the way, the more idiomatic approach would be to define a model. Model's allow you to handle this situation more gracefully and (in many cases) prevent you from tying your code to a specific RDBMS.

Resources