I would like to retrieve entity properties in a format like this: property_name: value.
I am trying to get the result this way:
public void retrievePerson(){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistence");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
String query = "MATCH (p:Person {id:3}) RETURN p.firstname, p.lastname";
List<Object[]> person = (List<Object[]>) em.createNativeQuery(query).getResultList();
em.flush();
tx.commit();
em.clear();
em.close();
emf.close();
}
catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}
}
I read somewhere the the object returned by the query is a managed entity.
I would like the result to be like this: {"firstname":"Jon", "lastname":"Smith"}
I have found this setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE which might be something that I am looking for but I am unable to get it to work.
Is there a way to achieve this?
Try changing your query to:
MATCH (p:Person {id:3})
RETURN { firstname: p.firstname, lastname: p.lastname }
If you are looking for the returned value to be an entity, this will work:
String query = "MATCH (p:Person {id:3}) RETURN p";
List<Person> person = (List<Person>) em.createNativeQuery(query, Person.class).getResultList();
Actually, in this case this would make more sense:
Person poem = (Person) em.createNativeQuer(query, Person.class).getSingleResult();
Related
i've come across a problem in these days, which would be simple for other languages, like php, but the project I'm doing is in Spring MVC.
The question is: In Spring MVC, how can i delete an entity with two attributes ids coming from this entity?
Example: "Delete from Entity Where id1 =: id1 and id2 =: id2" (This is the query that i want)
Thanks for the attention.
What i was trying ...
public boolean remover(int idUsuario, int idCategoria) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
EntityManager manager = factory.createEntityManager();
String hqlStr = "delete from UsuarioEscolheCategoria where idUsuario = :idUsuario and idCategoria = :idCategoria";
Query query = null;
try {
query = manager.createQuery(hqlStr);
query.setParameter("idUsuario", idUsuario);
query.setParameter("idCategoria", idCategoria);
query.executeUpdate();
manager.close();
factory.close();
return true;
}catch(Exception e) {
return false;
}
}
If i take the exception, it gives me:
String hqlStr = "delete from UsuarioEscolheCategoria where usuario.idUsuario = :idUsuario and categoria.idCategoria = :idCategoria";
The important part is usuario.idUsuario and categoria.idCategoria. That way you're making a reference to the attribute type Usuario, which is on your model class.
you prblem is the session factory, check how you have created it, here a simple usefull example:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
#Autowired
private SessionFactory sessionFactory;
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
public void deleteById(Integer id) {
Query query = getSession().createSQLQuery("delete from TABLE where id = :t_id");
query.setInteger("t_id", id);
query.executeUpdate();
}
public static int add_Book(String title, String auth_name, String publisher, String genre) {
Transaction tx = session.beginTransaction();
Query query = session.createQuery
("INSERT INTO Book(title,auth_name,publisher,genre)"
+ "SELECT "+title+", "+auth_name+", "+publisher+", "+genre);
tx.commit();
return query.executeUpdate();
and this error
Exception in thread "AWT-EventQueue-0"
java.lang.IllegalStateException: No data type for node:
org.hibernate.hql.internal.ast.tree.IdentNode +-[IDENT] IdentNode:
'q' {originalText=q}...
'q' is JTextField data
insert 'q' to 'title'
... Help would BE appreciated..
Just do it
public static void addBook(String title, String authName, String publisher, String genre) {
session.save(new Book(title, authName, publisher, genre));
}
Obviously, you should wrap that method with session/transaction control code.
And, please, always use Java Naming Convention!
auth_name, add_Book are incorrect names — use authName, addBook instead.
I think the answer of #v.ladynev is good but you can also try like this :
public static void addBook(String title, String authName, String publisher, String genre) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
// create book Object
Book book = new Book();
book.setTitle(title);
book.setAuthName(authName);
book.setPublisher(publisher);
book.setGenre(genre);
try {
tx = session.beginTransaction();
// Save the book to database
session.save(book);
tx.commit();
}catch(Exception e){
if (tx!=null) {
tx.rollback();}
e.printStackTrace();
}finally{
// close your session
session.close();
}
}
Use at least the Bean class to code "cleanly". We use the query only in special cases, otherwise we must at most avoid it in the code or use at least bundle resources.
Anything else checks that in your Book bean class you havesetAuthName and not setAuth_Name.
I call this method to convert hql query to sql:
public String toSql(String hqlQueryText) {
if (hqlQueryText != null && hqlQueryText.trim().length() > 0) {
QueryTranslatorFactory translatorFactory = new ASTQueryTranslatorFactory();
SessionFactoryImplementor factory = (SessionFactoryImplementor) sessionFactory;
QueryTranslator translator = translatorFactory.createQueryTranslator(hqlQueryText, hqlQueryText, Collections.EMPTY_MAP, factory, null);
translator.compile(Collections.EMPTY_MAP, false);
return translator.getSQLString();
}
return null;
}
and I have this filter in .hbm.xml file of domain class:
<filter name="userAuthorize" condition="some sql query here" />
but I don't know how I should tell hibernate to apply this filter when converting from hql to sql.
Assume that I call above method like this:
public Session getSession() {
try {
return sessionFactory.getCurrentSession();
}
catch (Exception e) {
}
return sessionFactory.openSession();
}
public List<DomainClass> getAll() {
String hql = " some hql query ";
Session session = getSession();
String sql = toSql(hql);
return session.createSQLQuery(sql).list();
}
Not a great Idea. But maybe It helps.
HQL and SQL have some differences, for instance with join , 'on' is used in SQL and 'with' is used in HQL.
So maybe you can use list of words that are unique to HQL and check for them in your String using
hql.contains("with") or hql.indexOf("with").
It is not the responsibility of the QueryTranslator to apply filters. Also, filters don't get applied to native SQL.
It looks like you just want to execute the HQL query? There is no need to have it translated to SQL first:
public List<DomainClass> getAll() {
String hql = " some hql query ";
return session.createQuery(hql).list();
}
I am trying to write unit testcases for the below code and am trying to mock the EntityManager implementation. I am unable to do so and I get null entity manager bean in my test class.
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp)
{
List<Object[]> result = null;
EntityManager em = null;
try {
query = String.format(query, startTime, endTimestamp, siteId);
logger.debug(" Query : " + query);
em = localContainerEntityManagerFactoryBean.nativeEntityManagerFactory.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
result = (List<Object[]>) em.createNativeQuery(query).getResultList();
//logger.debug("Results from the query : " + query + " are :" + Utility.toJsonString(result, true));
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Error Occurred while fetching the data for the query : " + query);
}
return result;
}
The test code I have written to mock it is below:
#InjectMocks
private LocalContainerEntityManagerFactoryBean emMock = new LocalContainerEntityManagerFactoryBean();
...
Mockito.when(localContainerEntityManagerFactoryBean.nativeEntityManagerFactory.createEntityManager()).thenReturn();
I should return a list when this is called as output So i need the whole method to be mocked. Please help !
First off all instead of #InjectMocks you should be using #Mock and put the #InjectMocks on the class you are trying to unit test.
However the fact that you are even considering mocking the LocalContainterEntityManagerFactoryBean is a sign that your code is flawed. You shouldn't be using the LCEMFB in code. It is only for configuration. It is a FactoryBean that creates an EntityManagerFactory so actually you should be injecting an EntityManagerFactory into your code which you should be mocking.
Instead of wiring the LCEMFB use the plain EMF and get an instance by annotating the field with #PersistenceUnit.
#PersistenceUnit
private EntityManagerFactory emf;
Then your method is also a bit cleaner
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp)
{
List<Object[]> result = null;
EntityManager em = null;
try {
query = String.format(query, startTime, endTimestamp, siteId);
logger.debug(" Query : " + query);
em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
result = (List<Object[]>) em.createNativeQuery(query).getResultList();
//logger.debug("Results from the query : " + query + " are :" + Utility.toJsonString(result, true));
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Error Occurred while fetching the data for the query : " + query);
}
return result;
}
However what you actually should be doing is injecting an EntityManager and don't try to create one yourself (your code is still flawed as you aren't closing the transaction nor the created EntityManager which in turn will eventually lead you to being unable to connect to your database as the underlying Connection remains open as well.
So instead of injecting either the LCEMFB or a EMF use a plain EntityManager instead and let spring manage it for you. To have spring manage the transaction make sure there is an #EnableTransactionManagement or <tx:annotation-driven /> in your configuration else it won't work.
#PersistenceContext
private EntityManager em;
Now your method is really focussed on what it should do, get data from the database.
#Transactional(readOnly=true)
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp) {
query = String.format(query, startTime, endTimestamp, siteId);
return em.createNativeQuery(query).getResultList();
}
Now in your test you should only need to mock the EntityManager.
All of this is also explained in the ORM chapter of the Spring Reference guide.
Another thing that worries me is that you are using a String and parsing that to be used as a query. This is potentially dangerous and a cause for SQL injection attacks. Instead of doing the formatting yourself you should let it be handled by Hibernate or JDBC.
#Transactional(readOnly=true)
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp) {
query = String.format(query, startTime, endTimestamp, siteId);
Query q = em.createNativeQuery(query);
q.setParameter("siteId", siteId)
.setParameter("startTime", startTime)
.setParameter("endTime", endTimestamp);
return q.getResultList();
}
The code above assumes a query in the form of SELECT * FROM YOURTABLE WHERE siteId=:siteId and startTime >= :startTime and endTime <= :endTime (or whatever your SQL looks like).
Tag is an entity and I remove tags with this method:
public static <T> boolean deleteById(Class<? extends BaseEntity> clazz, Long id) {
Session session = HibernateUtil.getSessionFactory().openSession();
try {
session.beginTransaction();
T e = get(clazz, id);
if (e != null) {
session.delete(e);
session.getTransaction().commit();
return true;
} else {
return false;
}
} finally {
session.close();
}
}
Next thing, I read the list with Tags again with this method:
public static List<Tag> listTags() {
Session session = HibernateUtil.getSessionFactory().openSession();
Query q = session.createQuery("FROM Tag tag");
List<Tag> tags = (List<Tag>) q.list();
session.close();
return tags;
}
The problem is that when deleting and reselecting all Tags the removed Tag is in the list although not in the database. when I run listTags() a second time, by clicking a link the object is removed and I get the correct list.
Does anyone know why?
Try to add flush() and use commit() like below:
...
session.delete(e);
session.flush();
session.beginTransaction().commit();
...
For more info go to session.getTransaction() vs session.beginTransaction()
I had a similar problem with Hibernate while migration from MySQL to MariaDB, were multiple transactions were being open and not closed...
the solution was removing the opening of the transactions as they were not required anyway....