I am trying to query JPA with Querydsl (4.1.4) as written here
http://www.querydsl.com/static/querydsl/latest/reference/html/ch02.html#jpa_integration . I use Hibernate (5.2.12.Final) as the JPA backend. I generate Querydsl query types from the JPA annotated classes using the apt-maven-plugin with the com.querydsl.apt.jpa.JPAAnnotationProcessor processor.
I have an issue while updating an entity : the updated value does not show up in the Java code. Here is the relevant code snippet that updates a boolean property (named success) in the Entity :
final EntityManagerFactory entityManagerFactory = PersistenceTestUtils.buildEntityManagerFactory();
final EntityManager entityManager = entityManagerFactory.createEntityManager();
final EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
final QJpaUpdateRound qJpaUpdateRound = QJpaUpdateRound.jpaUpdateRound;
final JPQLQueryFactory queryFactory = new JPAQueryFactory(entityManager);
final QJpaUpdateRound qJpaUpdateRound = QJpaUpdateRound.jpaUpdateRound;
final JPQLQueryFactory queryFactory = new JPAQueryFactory(entityManager);
final long roundId = 3L;
System.out.println("Original " +originalRound);
queryFactory //
.update(qJpaUpdateRound) //
.set(qJpaUpdateRound._success, true) //
.where(qJpaUpdateRound._id.eq(roundId)) //
.execute();
// entityManager.clear(); // Workaround
// Fetch the updated value
final UpdateRound updatedRound = queryFactory //
.selectFrom(qJpaUpdateRound) //
.where(qJpaUpdateRound._id.eq(roundId)) //
.fetchOne();
transaction.commit();
System.out.println("Updated "+ updatedRound);
This prints :
Original JpaUpdateRound{id=3; instant=2017-11-06T19:27:01.141Z;
success=false} Updated JpaUpdateRound{id=3;
instant=2017-11-06T19:27:01.141Z; success=false}
Also, an identity test on originalRound and updatedRound shows that both variables are the same instance.
I checked in the database : the value is really updated. And if I uncomment the following line
entityManager.clear(); // Workaround
The program prints
Original JpaUpdateRound{id=3; instant=2017-11-06T19:39:01.038Z;
success=false} Updated JpaUpdateRound{id=3;
instant=2017-11-06T19:39:01.038Z; success=true}
which is the result I expect.
It seems that the entity cache does not get updated when the Querydsl update is performed. Thus, it only returns the original Java object.
Why ? How can I synchronize the JPA backend and Querydsl ?
It appears there is no other way than manually tell the entity manager that it should refresh its data. Whether using entityManager.refresh(entity) on each entity that needs to be reloaded from the database; whether by clearing the whole entity manager cache by calling entityManager.clear().
See Force refresh of collection JPA entityManager
Related
I am only able to retrieve data and insert data in mongo DB v 3.4 using Hibernate OGM 5.1.0.Final. I am not able to perform delete operation or update operations. Can anyone help me out with an example?
This question is a bit vague, I'm not sure if you know how to delete an entity with Hibernate OGM and it's not working (in this case post an example of your code, please) or you don't know how JPA works. I will assume you don't know how to delete entities and add some examples on how to do it.
Using the session:
try ( Session session = openSession() ) {
Transaction transaction = session.beginTransaction();
Hypothesis entity = (Hypothesis) session.get( Hypothesis.class, hyp.getId() );
session.delete( entity );
transaction.commit();
}
Using the EntityManager (JPA):
final EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
Poem poem = em.find( Poem.class, poem.getId() );
em.remove( poem );
em.getTransaction().commit();
}
finally {
em.close();
}
Using the MonogDB CLI API:
try ( OgmSession session = openSession() ) {
Transaction transaction = session.beginTransaction();
String nativeQuery = "db.Poem.remove({ '_id': { '$numberLong': '11' } })";
Query query = session.createNativeQuery( nativeQuery ).addEntity( Poem.class );
query.executeUpdate();
}
About updates, I will leave it to the Hibernate ORM documentation.
If this doesn't answer your question please, try to elaborate more. Test cases are always appreciated.
I have an entity which contains a Map:
#OneToMany(fetch = FetchType.EAGER)
#JoinTable(name = "matrix_columns", joinColumns = Array(new JoinColumn(name = "id")))
#MapKey(name="tenor")
#Fetch(value = FetchMode.SELECT)
#Access(AccessType.PROPERTY)
def getInputMapNative: java.util.Map[Int,Column] = inputMap
And the Columncontains an Array
#(OneToMany #field)(cascade = Array(CascadeType.ALL))
#OrderColumn(name = "input_index")
#Fetch(value = FetchMode.SELECT)
var inputs:Array[Input] = _
Because I am stucked with Hibernate 3.6 and of this bug Failed to lazily initialize a collection, no session or session was closed (despite eagerly fetching), I tried to implement as a workaround the following:
I merge and save the columns
I update the map and merge and save the parent entity
(Since I can't rely on Hibernate cascading)
However, I still get an exception which I am not ready to solve
09:41:26.160 [GS-Notifier-pool-6-thread-2] ERROR o.h.util.JDBCExceptionReporter - Duplicate entry '781' for key 'inputs_id'
09:41:26.167 [GS-Notifier-pool-6-thread-2] ERROR o.h.e.d.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not insert collection: [Column.inputs#69]
This is my code that I would like to use both for creating or saving a new matrix in the database
val mergedColumns = matrix.getInputMap.map {
case(tenor,column) =>
column.inputs foreach{
item =>
val mergedItem = session merge item
session saveOrUpdate mergedItem
}
(tenor, (session merge column).asInstanceOf[Column])
}
matrix.setInputMapNative(mergedColumns)
val mergedMatrix = session merge matrix
session saveOrUpdate mergedMatrix
transaction.commit()
The exception is related to the uniqueness of the primary key inputs_id. Hibernate tries to insert the same entry twice, so I guess your way to merge and save the columns and update the map is the problem here.
Please consider Session.saveOrUpdate.
To get a better answer, please provide additional information like the code snippet you use to insert the new entry.
I would like to ask you for help with following problem. I have method:
String sql = "INSERT INTO table ...."
Query query = em.createNativeQuery(sql);
query.executeUpdate();
sql = "SELECT max(id) FROM ......";
query = em.createNativeQuery(sql);
Integer importId = ((BigDecimal) query.getSingleResult()).intValue();
for (EndurDealItem item : deal.getItems()) {
String sql2 = "INSERT INTO another_table";
em.createNativeQuery(sql2).executeUpdate();
}
And after executing it, data are not commited (it takes like 10 or 15 minutes until data are commited). Is there any way how to commit data explicitly or trigger commit? And what causes the transaction to remain uncommited for such a long time?
The reason we use nativeQueries is, that we are exporting data on some shared interface and we are not using the data anymore.
I would like to mention, that the transaction is Container-Managed (by Geronimo). EntityManager is created via linking:
#PersistenceContext(unitName = "XXXX", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
Use explicitly the transaction commit:
EntityManager em = /* get an entity manager */;
em.getTransaction().begin();
// make some changes
em.getTransaction().commit();
This should work. The time of execution of all operation between .begin() and .end() depends of course also from the cycle you're performing, the number of row you're inserting, from the position of the database (the speed of the network matters) and so on...
I want to update a specific field in the database Persons table by using HibernateTemplate. I am trying to do like this but this not working.
public void updateDate(int Id,Date receivedDate) {
Id = 10;
receivedDate = 2012-11-12;
String queryString = "update Persons set recievedDate=? where Id=? ";
getHibernateTemplate().update(queryString, new Object[] { Id, receivedDate });
}
I am getting an exception "UnkownEntity" when I run this query. Can I do update of a specific field at all by using HibernateTemplate? Is there any other alternate to do specific field update?
update method in getHibernateTemplate does not allow hql query to execute. It only allows hibernate entity object.
See link hibernate template update method
In your case Hibernate tries to resolve update Persons set recievedDate=? where Id=? as an entity.
Solution:
Query q = s.createQuery("update Persons set recievedDate=:recievedDate where Id=:Id");
q.setString("recievedDate", "some date");
q.setString("Id", "54");
q.executeUpdate();
Hope its clear.
You have to list your classes in your session factory configuration.
I assume your entity named Person
in HQL you must use java class name, not db table name
if HibernateTemplate is using, here is my solution.
// EntityName is the table to be updated
EntityName entity = hibernateTemplate.find("from EntityName where id=?" , id);
//set the value which has to be updated
entity.setValue(yourNewValue);
hibernateTemplate.SaveOrUpdate(entity);
// above updated the existing Entity table without duplicates
I have just set up a test that checks that I am able to insert entries into my database using Hibernate. The thing that drives me crazy is that Hibernate does not actually delete the entries, although it reports that they are gone!
The test below runs successfully, but when I check my DB afterwards the entries that were inserted are still there! I even try to check it using assert (yes I have -ea as vm parameter). Does anyone have a clue why the entries are not deleted?
public class HibernateExportStatisticDaoIntegrationTest {
HibernateExportStatisticDao dao;
Transaction transaction;
#Before
public void setUp(){
assert numberOfStatisticRowsInDB() == 0;
dao = new HibernateExportStatisticDao(HibernateUtil.getSessionFactory());
}
#After
public void deleteAllEntries(){
assert numberOfStatisticRowsInDB() != 0;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
for(PersistableStatisticItem item:allStatisticItemsInDB()) {
session.delete(item);
}
session.flush();
assert numberOfStatisticRowsInDB() == 0;
}
#Test public void exportAllSavesEntriesToDatabase(){
int expectedNumberOfStatistics = 20;
dao.exportAll(StatisticItemFactory.createTestStatistics(expectedNumberOfStatistics));
assertEquals(expectedNumberOfStatistics, numberOfStatisticRowsInDB());
}
private int numberOfStatisticRowsInDB() {
return allStatisticItemsInDB().size();
}
#SuppressWarnings("unchecked")
private List<PersistableStatisticItem> allStatisticItemsInDB(){
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
transaction = session.beginTransaction();
Query q = session.createQuery("FROM PersistableStatisticItem item");
return q.list();
}
}
The console is filled with
Hibernate: delete from UPTIME_STATISTICS where logDate=? and serviceId=?
but nothing has been deleted when I check it.
I guess it's related to inconsistent use of transactions (note that beginTransaction() in allStatisticItemsInDB() is called several times without corresponding commits).
Try to manage transactions in proper way, for example, like this:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = session.beginTransaction();
for(PersistableStatisticItem item:
session.createQuery("FROM PersistableStatisticItem item").list()) {
session.delete(item);
}
session.flush();
assert session.createQuery("FROM PersistableStatisticItem item").list().size() == 0;
tx.commit();
See also:
13.2. Database transaction demarcation
I have the same problem. Although I was not using transaction at all. I was using namedQuery like this :
Query query = session.getNamedQuery(EmployeeNQ.DELETE_EMPLOYEES);
int rows = query.executeUpdate();
session.close();
It was returning 2 rows but the database still had all the records. Then I wrap up the above code with this :
Transaction transaction = session.beginTransaction();
Query query = session.getNamedQuery(EmployeeNQ.DELETE_EMPLOYEES);
int rows = query.executeUpdate();
transaction.commit();
session.close();
Then it started working fine. I was using SQL server. But I think if we use h2, above code (without transaction) will also work fine.
One more observation : To insert and get records usage of transaction is not mandatory but for deletion of records we will have to use transaction. (only tested in SQL server)
Can you post your DB schema and HBM or Fluent maps? One thing that got me a while back was I had a ReadOnly() in my Fluent map. It never threw an error and I too saw the "delete from blah where blahblah=..." in the logs.