I am trying to update the existing rows in database table using JPA #Query Annotation. I want to perform Soft delete by updating the Deleted_Flag to YES from NO.
Here is my Code snippet:
#Modifying
#Query("UPDATE TBL_NAME SET DELETE_FLAG = 'YES' WHERE DELETE_FLAG = 'NO'
AND FILE_NM = :FILE_NM")
public void softDelete(#Param("FILE_NM") String fileName)
{
}
I am not getting any error, but data is not being updated in database.
Actual result must be like all the existing rows must be updated with DELETE_FLAG to YES.
Make sure you invoke the repository method with an active transaction.
Actually, in my last project I use the following idiom for updating a flag :
Entity is annotated with Hibernetish:
#Entity
#Table(name="myTable")
#Where(clause = "is_deleted = 0")
#Cacheable
public class MyTable {}
Actual update comes with a trivial find method:
#Transactional
public void deleteById(#NonNull final Long themeId) {
themeRepository.findById(themeId).orElseThrow(() -> new EntityNotFoundException(THEME_NOT_FOUND + themeId))
.setDeleted(true);
}
Related
I have the following code that first check record and if found delete that record and flush changes to the database. However, when I debug, I see that it does not reflect changes to the database when debugger hit the next code block (final Stock stock = new Stock();).
#Transactional
public CommandDTO createOrUpdate(StockRequest request) {
stockRepository.findByBrandUuidAndProductUuid(
request.getBrandUuid(),
request.getProductUuid())
.ifPresent(stock -> {
stockRepository.delete(stock);
stockRepository.flush();
});
final Stock stock = new Stock();
if (request.isOutOfStock()) {
stock.setBrandUuid(request.getBrandUuid());
stock.setProductUuid(request.getProductUuid());
stock.save(stock);
}
return CommandDTO.builder().uuid(stock.getUuid()).build();
}
So, what is the mistake in this approach?
JPA doesn't supports final field.
You can use two alternative solution for immutable class.
use #Immutable at entity class.
change entity class fields having only a getter.
I have a problem which I try to figure out since many hours now.
I must save a model with manual set id in the database using CrudRepository and Hibernate.
But the manual set of the id is ignored always.
Is it somehow possible, to force
CrudRepository.save(Model m)
to persist the given Model with UPDATE?
The queries always results in INSERT statements, without using the id.
The reason I must do this manually is, that the identifier is not the database ID - it is a ID generated outside as UUID which is unique over multiple databases with this model-entry. This model is shared as serialized objects via hazelcast-cluster.
Following an example:
The database already contains a Model-Entry with the id 1:
id identifier_field_with_unique_constraint a_changing_number
1 THIS_IS_THE_UNIQUE_STRING 10
Now I need to update it. I create a new Model version
Model m = new Model();
m.setIdentifierFieldWithUniqueConstraint(THIS_IS_THE_UNIQUE_STRING);
m.setAChangingNumberField(20);
saveMe(m);
void saveMe(Model m) {
Optional<Model> presentModalOpt = modelCrudRepo.findByIdentField(THIS_IS_THE_UNIQUE_STRING)
if(presentModalOpt.isPresent()) {
// The unique value in my identifier field exists in the database already
// so use that id for the new model, so it will be overwritten
m.setId(modalOpt.get().getId());
} else {
m.setId(null);
}
// This call will now do an INSERT, instead of UPDATE,
// even though the id is set in the model AND the id exists in the database!
modelCrudRepo.save(m);
// ConstraintViolationException for the unique identifier field.
// It would be a duplicate now, which is not allowed, because it uses INSERT instead of UPDATE
}
The id Field is tagged with #Id and #GeneratedValue annotation (for the case that the id is null and the id should be generated)
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
I even tried to changed this field only to an #Id field without #GeneratedValue and generate the ID always on my own. It had no effect, it always used INSERT statements, never UPDATE.
What am I doing wrong?
Is there another identifier for the CrudRepository that declares the model as an existing one, other than the id?
I'm happy for any help.
CrudRepository has only save method but it acts for both insert as well as update.
When you do save on entity with empty id it will do a save.
When you do save on entity with existing id it will do an update
that means that after you used findById for example and changed
something in your object, you can call save on this object and it
will actually do an update because after findById you get an object
with populated id that exist in your DB.
In your case you are fetching the records based on a field (unique) But records will update only when the model object has a existing primary key value
In your code there should be presentModalOpt instead of modalOpt
void saveMe(Model m) {
Optional<Model> presentModalOpt = modelCrudRepo.findByIdentField(THIS_IS_THE_UNIQUE_STRING)
if(presentModalOpt.isPresent()) { // should be presentModalOpt instead of modalOpt
} else {
m.setId(null);
}
modelCrudRepo.save(m);
}
See the default implementation -
/*
* (non-Javadoc)
* #see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
*/
#Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
I am new to spring data jpa. I have a scenario where I have to create an entity if not exists or update based on non primary key name.Below is the code i wrote to create new entity,it is working fine,but if an already exists record ,its creating duplicate.How to write a method to update if exists ,i usually get list of records from client.
#Override
#Transactional
public String createNewEntity(List<Transaction> transaction) {
List<Transaction> transaction= transactionRespository.saveAll(transaction);
}
Add in your Transaction Entity on variable called name this for naming as unique:
#Entity
public class Transaction {
...
#Column(name="name", unique=true)
private String name;
...
}
Then you won't be able to add duplicate values for name column.
First, this is from google composite key means
A composite key is a combination of two or more columns in a table that can be used to uniquely identify each row in the table when the columns are combined uniqueness is guaranteed, but when it taken individually it does not guarantee uniqueness.
A composite key with an unique key is a waste.
if you want to update an entity by jpa, you need to have an key to classify if the entity exist already.
#Transactional
public <S extends T> S save(S entity) {
if(this.entityInformation.isNew(entity)) {
this.em.persist(entity);
return entity;
} else {
return this.em.merge(entity);
}
}
There are two ways to handle your problem.
If you can not get id from client on updating, it means that id has lost its original function. Then remove your the annotation #Id on your id field,set name with #Id. And do not set auto generate for it.
I think what you want is an #Column(unique = true,nullable = false) on your name field.
And that is the order to update something.
Transaction t = transactionRepository.findByName(name);
t.set.... //your update
transactionRepository.save(t);
I try to use handle query for updating table in the SQL database.
Code:
#Autowired
private ProducerRepository producerRepository;
public void update(Producer producer){
String name = producer.getProducerName();
long id = producer.getId();
// producerRepository.save(producer); //this method works well.
producerRepository.update(name, id); //handle attempt - throws exeption in this string
}
ProducerRepository:
#Repository
public interface ProducerRepository extends JpaRepository<Producer, Long>{
#Query(nativeQuery = true, value = "UPDATE producer SET producer_name = :pName WHERE id = :id")
Producer update(
#Param("pName") String pName,
#Param("id") long id
);
}
All parameters of the producer entity are correct and producerRepository.save(producer) works well.
(also I out in console name and id fields - all right)
So, I can save producer in the database, but, when I try to use update() method I get the error.
Can not issue data manipulation statements with executeQuery()
PS
sql query in the console also works well
(UPDATE producer SET producer_name = 'some name' WHERE id = ....)
It should be noted that other SQL native queries in repository work correctly. So the spring/hibernate/jdbc settings are correct.
Use annotation #Modifying.
This will trigger the query annotated to the method as updating query
instead of a selecting one.
From 2.2.6 Modifying queries https://docs.spring.io/spring-data/jpa/docs/1.3.4.RELEASE/reference/html/jpa.repositories.html
In case above solution not work use this
#Modifying
#Transactional
#Query(value ="delete from admindata where user_name = :userName AND group_name = :groupName",nativeQuery = true)
public void deleteadminUser(#Param("userName") String userName,#Param("groupName") String groupName);
#Query(nativeQuery = true, value = "UPDATE producer SET producer_name = :pName WHERE id = :id")
Producer update(
#Param("pName") String pName,
#Param("id") long id
);
your update method is returning Producer Object, the return should be either int or void, since you are returning Producer entity, Spring JPA is thinking that it has to fetch the object instead of updating it, that is the reason it is executing executeQuery, instead of executeUpdate and also you need to #Modifying annotation.
I have implemented a solution of Hibernate Envers.
I am extending RevisionLister by creating my own class to store the system username:
import org.hibernate.envers.RevisionListener;
public class CustomRevisionListener implements RevisionListener {
public void newRevision(Object revisionEntity) {
CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity;
revision.setUsername(System.getProperty("user.name")); // for testing
}
}
This does the job, but what I want to do, is to make a more comprehensive record, that would include the table name being audited.
Does anyone know how I could do this. I cannot find any documentation relating to recording the table name?
See example 15.2 in the envers doc how to get the modified entity class(es). Then slightly change the code to obtain the table name from the entity class (assumes you use JPA/Hibernate annotations on entity classes):
public class CustomEntityTrackingRevisionListener
implements EntityTrackingRevisionListener {
#Override
public void entityChanged(Class entityClass, String entityName,
Serializable entityId, RevisionType revisionType,
Object revisionEntity) {
// either javax.persistence.Table or org.hibernate.annotations.Table
Table tableAnnotation = entityClass.getAnnotation(Table.class);
if (tableAnnotation != null)
String tableName = tableAnnotation.getName();
((CustomTrackingRevisionEntity)revisionEntity).addTable(tableName);
}
}
I don't know if Envers can track the table name of the records being audited out of the box , but I know it can track the entity name instead which can be enabled by three different ways
You can extend DefaultTrackingModifiedEntitiesRevisionEntity, or configure org.hibernate.envers.track_entities_changed_in_revision parameter to true.
See Envers Doc: Tracking entity names modified during revisions