I have a problem with hibernate native sql join query. My query is below and works on Mysql db.
SELECT c.cart_id, u.name, u.surname, c.totalPrice
FROM sandbox.cart c JOIN
sandbox.user u
ON u.id = c.placedBy
I am using hibernate in code and encountered an exception
java.sql.SQLException: Column 'id' not found.
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1093)
Query in code here
Session session = hibernateUtil.getSessionFactory().getCurrentSession();
SQLQuery query = session.createSQLQuery(ORDER_PER_USER_QUERY);
query.addEntity(OrderPerUser.class);
return query.list();
Table column name
Cart
| cart_id | placedBy | totalPrice
User
| id | email | name | surname
My mapped class is
#Entity
public class OrderPerUser {
#Id
private long id;
private String name;
private String surName;
private long cartId;
private double totalPrice; }
You need to remove the line:
query.addEntity(OrderPerUser.class);
After that, you need to rewrite the code and map your object manually, because your OrderPerUser is not an entity:
Session session = hibernateUtil.getSessionFactory().getCurrentSession();
SQLQuery query = session.createSQLQuery(ORDER_PER_USER_QUERY);
List<OrderPerUser> returnList new ArrayList<>();
for(Object[] row : query.list()){
OrderPerUser orderPerUserObj = new OrderPerUser();
oderPerUserObj.setCartId(Long.parseLong(row[0].toString()));
//put other properties here
returnList.add(orderPerUserObj);
}
return returnList;
Edit1: Now I see that you added the mapped class, but OrderPerUser should not be an entity in your case, but a regular DTO. An entity requires an ID, but you can't select the ID in this case, because OrderPerUser is not part of a table, it is just some selected data that you want in your memory and not in the database. So you should make your OrderPerUser a regular data transfer object.
Please read about entities, data transfer objects, data access objects to see what each object should do.
My guess is that your OrderPerUser class which you try to use for collecting the result is expecting a column with name id, and you have no such column in your query...
Try using the query:
SELECT u.id, c.cart_id, u.name, u.surname, c.totalPrice
FROM sandbox.cart c
JOIN sandbox.user u ON u.id = c.placedBy
Related
I am trying to join multiple tables and to map the table columns to list of user objects.
Below is the SQL query and I am trying to convert to ORM using Hibernate Criteria:
SELECT table1.domainname, table2.policyname,table3.filterpath,table4.userdirectoryname
FROM table1, table2,table3, table4
WHERE table3.domainoid = table1.domainoid
AND table3.policyoid = table2.policyoid
AND table3.userdirectoryoid = table4.userdirectoryoid
AND table1.domainname = 'admin'
From the above query, we will get a list of user objects and trying to map the results to the user object. Below is the POJO class of the user object to form.
public class DomainDetails {
String domainName, policyName, filterPath, userDirName;
public DomainDetails(String domainName, String policyName, String filterPath, String userDirName) {
super();
this.domainName = domainName;
this.policyName = policyName;
this.filterPath = filterPath;
this.userDirName = userDirName;
}
// getters and setters...
}
How to join the multiple tables and the mapping of the respective columns to the user object?
appreciate the help..thanks
You can use mapping annotation ..
Mapping entity associations/relationships
I have performance problems with the group by feature in Hibernate. Consider this 2 classes:
public class Project
{
...
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="user")
private User user;
...
}
public class User
{
...
private Integer id;
private String name;
...
}
Now I try to get a list of all Users assigned to the project. But this query is uselessly slow (more than 100'000 project entries, a lot of joins):
Session session = this.sessionFactory.openSession();
String SQL="SELECT user.id as id, user.name as name FROM Project p GROUP BY p.user.id";
Query q = session.createQuery(SQL);
q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List<Object> list = q.list();
session.close();
I try to change the query this way, but this is not working either because the variable user is an Object (but this would work as a native SQL query):
SELECT id, name FROM User WHERE id IN(SELECT user FROM Project GROUP BY user)
Any other ideas? Thank you in advance!
Try creating an index from the foreign key column.
#javax.persistence.Table(name = "project")
#Table(appliesTo = "project" ,indexes = #Index(columnNames = "user", name = "user_index"))
#Entity
public class Project
{
..
Update
columnNames has been depricated. Use columnList instead.
#Index(columnList = "user", name = "user_index")
Hope this helps.
I doubt this has to do with Hibernate being slow. Most probably the SQL query is slow if run directly on the database as well.
One good practice is to create indices whenever you have a foreign key in your table. In your case create an index for user_id on your project table and run the query once more.
If you want to get all users assigned to the project you don't need group by. Do something like this
select user from Project project inner join project.user user where project.id = :projectId
I am new in JPA and I have a problem when I try to query to the database using MAX() function.
Code of my function is following. Can anyone help me? Thank you.
public int getMaxId(){
entityManager = this.entityManagerFactory.createEntityManager();
Query query = entityManager.createQuery("SELECT * FROM user WHERE id = (SELECT MAX(u.id) FROM user u)");
User user = (User) query.getSingleResult();
int id = user.getId();
return id;
}
I am using JPA, TopLink and Apache Derby. My method should return the maximum id of table users.
Edit: I call that function from a service:
try {
int id = userDAO.getMaxId();
logger.info("Max id: " + id);
user.setId(id+1);
}
catch (Exception ex){
logger.error("Unable to get the max id.");
}
Value of user.setId() is always '0'.
Edit(2): Log
Caused by: Exception [EclipseLink-8034] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Error compiling the query [SELECT u FROM user u WHERE u.id = (SELECT MAX(uu.id) FROM user uu)]. Unknown entity type [user].
at org.eclipse.persistence.exceptions.JPQLException.entityTypeNotFound(JPQLException.java:483)
at org.eclipse.persistence.internal.jpa.parsing.ParseTreeContext.classForSchemaName(ParseTreeContext.java:138)
at org.eclipse.persistence.internal.jpa.parsing.SelectNode.getClassOfFirstVariable(SelectNode.java:327)
at org.eclipse.persistence.internal.jpa.parsing.SelectNode.getReferenceClass(SelectNode.java:316)
at org.eclipse.persistence.internal.jpa.parsing.ParseTree.getReferenceClass(ParseTree.java:436)
at org.eclipse.persistence.internal.jpa.parsing.ParseTree.adjustReferenceClassForQuery(ParseTree.java:75)
at org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree.populateReadQueryInternal(JPQLParseTree.java:103)
at org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree.populateQuery(JPQLParseTree.java:84)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:219)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:190)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:142)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:126)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1475)
... 35 more
My entity User is declared as follows:
#Entity
#Table(name = "user")
public class User {
#Id
private int id;
private String name;
private String lastName;
private String city;
private String password;
You can directly use more simple JPQL
return (Integer)entityManager.createQuery("select max(u.id) from User u").getSingleResult();
Or use TypedQuery
return entityManager.createQuery("select max(u.id) from User u", Integer.class).getSingleResult();
EDIT:
Unknown entity type [user]
You should use User instead of user.
Well it is hard to say from your comments and you haven't posted any logging.
How about this:
Query query = entityManager.createQuery("SELECT u FROM users u WHERE u.id = (SELECT MAX(u.id) FROM users u)");
Im Using that code:
Query qry = em.createQuery("SELECT MAX(t.column) FROM Table t");
Object obj = qry.getSingleResult();
if(obj==null) return 0;
return (Integer)obj;
Cause if there is no elements on Table "t", NullpointerException is throwing.
It's a good solution, but you have to use different names in tho two part of sql. Like this:
"SELECT u FROM users u WHERE u.id = (SELECT MAX(u2.id) FROM users u2)"
Hibernate is generating invalid SQL for a particular criteria query. I can manually fix the query by adding single quotes to the value being used in the WHERE clause.
To fix it, I changed the query from:
where (role0_.ROLE_ID=2L )
to:
where (role0_.ROLE_ID=`2L` )
How to force hibernate to add single quotes (in mysql it is single quotes but in other database systems it might be something else) to enclose the values used in generated SQL queries?
The full generated query is:
select permission1_.PERMISSION_ID as PERMISSION1_12_,
permission1_.IS_REQUIRED as IS2_12_,
permission1_.SOURCE_ROLE_ID as SOURCE3_12_,
permission1_.TARGET_ROLE_ID as TARGET4_12_
from (
select ROLE_ID,
NAME,
DESCRIPTION,
IS_ACTION,
LABEL,
null as FIRST_NAME,
null as LAST_NAME,
null as PASSWORD_HASH,
1 as clazz_ from GROUPS
union
select ROLE_ID,
NAME,
null as DESCRIPTION,
null as IS_ACTION,
null as LABEL,
FIRST_NAME,
LAST_NAME,
PASSWORD_HASH,
2 as clazz_ from USERS
)
role0_ inner join PERMISSIONS permission1_ on role0_.ROLE_ID=permission1_.SOURCE_ROLE_ID
where (role0_.ROLE_ID=2L )
Basically I'd like this single quotes to be added by Hibernate.
The criteria query that generated this query is:
EntityManager entityManager = getEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();
Class<?> queryScopeClass = temp.pack.commons.user.Role.class;
Root<?> from = criteriaQuery.from(queryScopeClass);
Path<?> idAttrPath = from.get("id");
// also tried criteriaBuilder.equal(idAttrPath, new Long(2))
Predicate predicate = criteriaBuilder.equal(idAttrPath, criteriaBuilder.literal(new Long(2)))
criteriaQuery.where(predicate);
Path<?> attributePath = from.get("permissions");
PluralAttributePath<?> pluralAttrPath = (PluralAttributePath<?>)attributePath;
PluralAttribute<?, ?, ?> pluralAttr = pluralAttrPath.getAttribute();
Join<?, ?> join = from.join((SetAttribute<Object,?>)pluralAttr);
TypedQuery<Object> typedQuery = entityManager.createQuery(criteriaQuery.select(join));
return (List<P>)typedQuery.getResultList();
Please let me know if you have any clues on how to force Hibernate to add those single quotes to the values (not the column/table name).
In my entity Role, the id property that appears in the WHERE clause is of long type, of course.
Follow up: The type of the id column in the database is bingint:
+---------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+-------+
| ROLE_ID | bigint(20) | NO | PRI | NULL | |
...
This is how the Role class has been annotated:
#Entity(name="Role")
#Table(name = "ROLES")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#javax.persistence.TableGenerator(
name="GENERATED_IDS",
table="GENERATED_IDS",
valueColumnName = "ID"
)
public abstract class Role implements Serializable {
private static final long serialVersionUID = 1L;
/**
* The id of this role. Internal use only.
*
* #since 1.0
*/
#Id #GeneratedValue(strategy = GenerationType.TABLE, generator="GENERATED_IDS")
#Column(name = "ROLE_ID")
protected long id;
/**
* Set of permissions granted to this role.
*
* #since 1.0
*/
#OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy="sourceRole")
protected Set<Permission> permissions = new HashSet<Permission>();
...
}
I use table per class inheritance strategy, that's why you see the union in the generated query for User and Group entities. They extend Role. Id is defined in Role.
Thank you!
Eduardo
The hibernate property hibernate.globally_quoted_identifiers=true will do the trick
Change your id to the Long class type instead of a primitive. Hibernate will then simply generate the query to be ROLE_ID=2, which is 100% valid since numbers don't require ticks or quotes.
I have (non-Hibernated) database tables that contain ids for Hibernate entities. I can query them (using createSQLQuery), which gives me the ids, from which I can then load the entities.
I'd like to do that in one step, and I think I can do that with addEntity, but I am not sure how exactly. (Hibernate's documentation web site is down. Again.) I can use addEntity when all the columns for the entity table are present, but I have only the id now.
This complains about the missing columns:
return (List<MyEntity>) session.createSQLQuery(
"select entity_id from the_table where foreign_key_value = ?")
.addEntity("entity_id", MyEntity.class)
.setLong(0, foreignKey).list();
I think you want something like:
session.createSQLQuery("select {entity.*} from entity_table {entity} where ....")
.addEntity("entity", Entity.class).(bind-parameters).list();
Hibernate will expand "{entity.*}" to be the relevant columns from entity_table.
Although if you already have the IDs, you can simply use session.load() to convert those to actual instances (well, lazy-load proxies).
i would use a join
select *
from entity_table
where entity_id = (select entity_id
from non_hibernate_table
where id = ?)
For oracle dialect. If u have problem with mapping database column type to java data type u can set it manually like that: .addScalar("integerFieldName", Hibernate.INTEGER)
public class LookupCodeName
{
private String code;
private String name;
/*... getter-setters ... */
}
public class someBL {
public List<LookupCodeName> returnSomeEntity() {
SQLQuery sqlQuery = (SQLQuery)((HibernateSession)em).getHibernateSession()
.createSQLQuery( "SELECT st.name as name, st.code as code FROM someTable st")
.addScalar("code")
.addScalar("name")
.setResultTransformer(Transformers.aliasToBean(LookupCodeName.class));
}
return (List<LookupCodeName>)sqlQuery.list();
}