I have entity Student with two fields: id, name
I save it in the base using entityManager persist()
next, using JPQL I update one entity and get it.
Data in the entity is old. Why?
but in the DB all data of entity is changing.
public class Main {
public static void main(String[] args) {
EntityManagerFactory myFactory = Persistence.createEntityManagerFactory("myPerName777");
EntityManager entityManager = myFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(new Student("max"));
entityManager.persist(new Student("max"));
entityManager.persist(new Student("max"));
entityManager.persist(new Student("mike"));
entityManager.persist(new Student("mike"));
transaction.commit();
transaction.begin();
Query query = entityManager.createQuery("UPDATE Student s set s.userrname='JOHN' where s.id=1");
query.executeUpdate();
transaction.commit();
Student student = entityManager.find(Student.class,1);
System.out.println(student.getUserrname());
entityManager.close();
myFactory.close();
}
}
This code return Max, but in the DB date is changing.
How can I return actual data?
With executeUpdate you execute a SQL statement (modifying directly the DB) but do not change the Entity loaded/managed by Hibernate, hence you hold stale data in your application.
The best approach is to always work with the Hibernate entities which are managed by Hibernate and kept in the first-level cache. Your data stays in synch with the DB.
If you really need to run a statement (for example because it is a complex statement or performs much better) you need to evict the Entity and reload it again from the DB.
Related
I have a simple table and I want to store them in another table aswell (create a historic of users). Let's call it Users. I created a table exactly like Users (only different id name) called HISTORY_Users.
So I created the table and now I realize that I have 2 tables for 1 object. So how do I add my object only to the hist table?
I dont want to add them at the same time. I want to add the user to the hist only when he deletes the accounts.
I'm using Hibernate with xml mapping
//when the user deletes the account I call this function and pass the User
private static void addToHist(User User) {
//how do I add only to HIST_Users table??
Database.addToDatabase(user);
}
//Save the object to the database
public static void addToDatabase(Object object) {
SessionFactory factory = HibernateUtil.GetSessionFactory();
Session session = factory.openSession();
Transaction tx = null;
try{
tx = session.beginTransaction();
session.save(object);
tx.commit();
}catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}finally {
session.close();
}
}
Maybe better solution will be use the Hibernate Envers: http://hibernate.org/orm/envers/
You can configure when you want to put it into history: on create, update or delete.
Tables are created automatically, you need to add some annotations only like #Audited etc.
I need to audit updates, inserts and deletes, i'm using eclipselink as JPA provider. I need to store all modified data.
I tried to use #PrePersist for the merge but i don't know why, it is not called, and it's not possible to pass a object as my data before.
Other problem is that in update transactions i will need to store data as it was before and after the transaction to do a comparison, same in deleting, i need to store data that was deleted.
What is the best way to do this?
#Entity
#EntityListeners(FrotaListener.class)
#Table(name="frota" , schema="sap")
#NamedQuery(name="Frota.findAll", query="SELECT f FROM Frota f")
public class Frota implements Serializable {..}
public class FrotaListener {
#PrePersist
#PreUpdate
#PreRemove
private void beforeAnyOperation(Object object) {
System.out.println("teste");
}
}
try {
em.getTransaction().begin();
em.flush();
em.merge(frota);
em.flush();
em.getTransaction().commit();
} catch (Exception e) {
sqlErrorParse(e);
e.printStackTrace();
}finally {
em.close();
}
and FrotaListener is never called
I want to perform multiple updates on an #Entity. But based on some evaulations, I have to execute long running tasks in between. The task itself is based on a property of that entity. Thus, I first have to fetch the entity, merge some content, run the long task, and merge again.
This would span the database transaction, which is probably not correct:
#Transactional
public void update(DTO dto) {
entity = findOne(dto.id);
updateEntityFieldsFromDTO(entity, dto);
if (entity.hasTaskCondition) {
result = runLongTask(entity.property); //spanning the tx
mergeResultIntoEntity(entity, result);
}
}
Problem: the runLongTask() will block the transaction and keep the database connection open maybe for a long time, without interaction on the db.
Thus I thought creating single #Transactional methods, and running the task ouside of those tx:
//wrapper method without a transaction
public void updateFacade(DTO dto) {
entity = service.update(dto.id);
if (entity.hasTaskCondition) {
//running outside the transaction
result = runLongTask(entity.property);
service.mergeResultIntoEntity(entity.id, result);
}
}
Then my transactional methods would be as follows:
#Transactional
public Entity update(DTO dto) {
//first select the entity
entity = findOne(dto.id);
//then merge the content
updateEntityFieldsFromDTO(entity, dto);
return entity;
}
#Transactional
public Entity mergeResultIntoEntity(id, result) {
//again select the entity
entity = findOne(dto.id);
//now merge result into entity within tx
return entity;
}
Question: is it correct to always pass the entity.id to the #Transactional methods, and then fetch the object from db again inside those tx methods?
I think I cannot pass the entity directly into the #Transactional methods from updateFacade, as the entity is detached. Correct?
I'm new to hibernate and as I researched, I have found out that the HQL insert query gets data from other tables. According to what I've read, I can make use of session.save for the insert functionality.
In my DAO I have this addToCart() method
#Override
public void addToCart(ShoppingCart cart) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.save(cart);
transaction.commit();
session.close();
}
The code above doesn't work. Maybe I am missing something because I'm still new to hibernate.
I'm using Jersey and am expecitng a POST as an entity. However thst POST will also contain the UUID for one of its relationships:
Jersey Resource:
#POST
public WorkstationEntity save (WorkstationEntity workstationEntity) {
//WorkflowProcessEntity workflowProcessEntity = workflowProcessService.findByUUID();
workstationService.save(workstationEntity);
return workstationEntity;
}
How can I adjust the following mapping so it'll recognize the relationship and save correctly? Currently the workflow_process_id is NULL when it's saved and I have to query for the entity manually.
The JSON being posted is... {name: Workstation 1; workflow_process_id: 1}
private WorkflowProcessEntity workflowProcess;
#ManyToOne
#JoinColumn(name = "workflow_process_id", referencedColumnName = "id")
public WorkflowProcessEntity getWorkflowProcess() {
return workflowProcess;
}
public void setWorkflowProcess(WorkflowProcessEntity workflowProcess) {
this.workflowProcess = workflowProcess;
}
workstationService
#Transactional
public void save(WorkstationEntity workstationEntity) {
workstationRepository.save(workstationEntity);
}
Can you show code for workstationService? are you using Hibernatr or simple jdbc or any other orm tool?
I think inside workstationService.save(workstationEntity); you will need to attach workstationEntity to session (in case of Hibernate Hibernate Session). and then save it..
If I understand the problem it is that the returning json has a null id for the attached WorkstationProcessEntity id field. This is most likely a problem when you are trying to persist / merge the entity the transaction is not being committed before returning the detached entity. If you are using a persist make sure that you commit the transaction otherwise the id's will be null. Otherwise if you are using a merge this will commonly fix the problem.
protected T persist(T obj) {
EntityManager em = ThreadLocalPersistenceManager.getEntityManager();
EntityTransaction tx = em.getTransaction();
try {
if (! tx.isActive()) {
tx.begin();
}
em.persist(obj);
} finally {
if (!tx.getRollbackOnly()) {
tx.commit();
}
}
return obj;
}
The other likely cause is that your fetch is not set to eager so the datastore will only fetch the entity when it is accessed and by the time you are returning from the post the child entity is not attached. This is the most likely cause for your problem. What you should try is to access the workstation entitites getWorkflowProcess before closing the entity manager. Otherwise the attached entities will be null. Or add the FetchType.Eager annotation to fetch the child entities from the database when the parent is accessed.