hibernate "where" query only works for id field - java

I have a problem with a Hibernate query that looks as follows:
List persons = getList("FROM creator.models.Person p WHERE p.lastName="+userName);
(the getList(String queryString) method just executes the query using a session factory.)
This is my person class:
#Entity
#Table(name="persons")
public class Person{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name="first_name", nullable=false, updatable=true)
private String firstName;
#Column(name="last_name", nullable=false, updatable=true)
private String lastName;
/// etc
And this is the table:
CREATE TABLE persons(
id INTEGER NOT NULL AUTO_INCREMENT,
first_name CHAR(50),
last_name CHAR(50),
abbreviation CHAR(4),
PRIMARY KEY (id)
);
Searching for a person with the name TestName, I get an exception with this message:
org.hibernate.exception.SQLGrammarException: Unknown column 'TestName' in 'where clause'
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:82)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
//etc
The query created by Hibernate looks like this:
INFO: HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select person0_.id as id8_, person0_.abbreviation as abbrevia2_8_, person0_.first_name as first3_8_, person0_.last_name as last4_8_ from persons person0_ where person0_.last_name=TestName
Dec 10, 2012 5:14:26 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
Searching for the id (...WHERE p.id="3") works fine, by the way!
I hope somebody knows what is going wrong because for me the query looks right and I can't find out why the lastName is seen as a column name suddenly.

You need to put userName in quotes:
"FROM creator.models.Person p WHERE p.lastName='"+userName+"'";
Or (which is much better) to use parameters

replace your hql with:
Query query = session.createQuery("from creator.models.Person p where p.lastName = ?")
.setParameter(0, userName);
List persons = query.list();
that way you also prevent sql-injection.

you need to wrap your parameter with single quotes:
List persons = getList("FROM creator.models.Person p WHERE p.lastName='"+userName+"'");
but much better with a parameterized query:
String hql = "FROM creator.models.Person p WHERE p.lastName= :userName";
Query query = session.createQuery(hql);
query.setString("userName",userName);
List results = query.list();

Related

How to translate this SQL (or similar) to Criteria JPA

I have this SQL and need to parse to Criteria JPA. I read than I can't use UNION in JPA, so I need a similar solution.
I have 3 tables (with same fields) and need to union for print in datatable.
The query is:
SELECT * FROM (
SELECT id, project_id, start_date, end_date, 'cs' FROM construction_shares
UNION
SELECT id, project_id, start_date, end_date, 'ips' FROM intervention_pr_shares
UNION
SELECT id, project_id, start_date, end_date, 'is' FROM intervention_shares
) AS t ORDER BY START_DATE ASC;
Can someone help me?
Thanks a lot!
Criteria JPA dont support UNION, you can try two options.
Create a native query and execute from entityManager with a List of POJOS as result.
Throw 3 Querys like this:
SharesPojo:
private Integer id;
private Integer projectId;
private Date startDate;
private Date endDate
public SharesPojo(Integer id, Integer projectId, Date startDate, Date endDate);
DAO:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SharesPojo> csQuery = cb.createQuery(SharesPojo.class);
Root<ConstructionShares> csRoot = csQuery.from(ConstructionShares.class);
csQuery.multiselect(
csRoot.get(ConstructionShares_.id)
csRoot.get(ConstructionShares_.projectId)
csRoot.get(ConstructionShares_.startDate)
csRoot.get(ConstructionShares_.endDate)
);
CriteriaQuery<SharesPojo> ipsQuery = cb.createQuery(SharesPojo.class);
Root<InterventionPrShares> ipsRoot = ipsQuery.from(InterventionPrShares.class);
ipsQuery.multiselect(
ipsRoot.get(InterventionPrShares_.id)
ipsRoot.get(InterventionPrShares_.projectId)
ipsRoot.get(InterventionPrShares_.startDate)
ipsRoot.get(InterventionPrShares_.endDate)
);
CriteriaQuery<SharesPojo> isQuery = cb.createQuery(SharesPojo.class);
Root<InterventionShares> isRoot = isQuery.from(InterventionShares.class);
isQuery.multiselect(
isRoot.get(InterventionShares_.id)
isRoot.get(InterventionShares_.projectId)
isRoot.get(InterventionShares_.startDate)
isRoot.get(InterventionShares_.endDate)
);
List<SharesPojo> unionList = new ArrayList<>();
unionList.addAll(em.createQuery(csQuery).getResultList());
unionList.addAll(em.createQuery(ipsQuery).getResultList());
unionList.addAll(em.createQuery(isQuery).getResultList());

JPA native sql query mapping error?

I have a JPA entity MyEntity which includes a composite primary key in a #Embeddable class MyEntityPK.
I am using a native sql query in method getThreeColumnsFromMyEntity():
public List<MyEntity> getThreeColumnsFromMyEntity() {
List<MyEntity> results = em.createNativeQuery("select pid,name,dateofbirth from (select pid,name, dateofbirth,max(dateofbirth) "
+ "over(partition by pid) latest_dateofbirth from my_entity_table) where"
+ " dateofbirth = latest_dateofbirth;","myEntityMapping").getResultList();
return results;
My #SqlResultSetMapping:
#SqlResultSetMapping(
name = "myEntityMapping",
entities = {
#EntityResult(
entityClass = MyEntityPK.class,
fields = {
#FieldResult(name = "PID", column = "pid"),
#FieldResult(name = "NAME", column = "name")}),
#EntityResult(
entityClass = MyEntity.class,
fields = {
#FieldResult(name = "dateofbirth", column = "dateofbirth")})})
My JPA columns are named : #Column(name="DATEOFBIRTH"), "PID" and "NAME".
I tested my sql statement straight on the db and it works fine.
When i run it on Eclipse I get an Oracle error:
ORA-00911 and "Error code 911 , Query: ResultSetMappingQuery [..]
My guess is there is something wrong with the mapping but I cannot find out what it is.
I assume you get this error because you are missing the alias name for the subquery, so instead you can try this :
select
pid,
name,
dateofbirth
from
(
select
pid,
name,
dateofbirth,
max(dateofbirth) over(partition by pid) AS latest_dateofbirth
from
my_entity_table
) second_result
-- ^--------------- use an aliase name to the subquery
where
second_result.dateofbirth = latest_dateofbirth
-- ^----use the aliase name to reference to any of its fields, in your case 'dateofbirth'
Take a look about the error meaning here ORA-00911: invalid character tips

JPQL include elementCollection map in select statement

I have an #Entity class Company with several attributes, referencing a companies Table in my db. One of them represents a Map companyProperties where the companies table is extended by a company_properties table, and the properties are saved in key-value format.
#Entity
#Table(name = "companies")
public class Company extends AbstractEntity {
private static final String TABLE_NAME = "companies";
#Id
#GeneratedValue(generator = TABLE_NAME + SEQUENCE_SUFFIX)
#SequenceGenerator(name = TABLE_NAME + SEQUENCE_SUFFIX, sequenceName = TABLE_NAME + SEQUENCE_SUFFIX, allocationSize = SEQUENCE_ALLOCATION_SIZE)
private Long id;
//some attributes
#ElementCollection
#CollectionTable(name = "company_properties", joinColumns = #JoinColumn(name = "companyid"))
#MapKeyColumn(name = "propname")
#Column(name = "propvalue")
private Map<String, String> companyProperties;
//getters and setters
}
The entity manager is able to perform properly find clauses
Company company = entityManager.find(Company.class, companyId);
However, I am not able to perform JPQL Queries in this entity and retrieve the Map accordingly. Since the object is big, I just need to select some of the attributes in my entity class. I also do not want to filter by companyProperties but to retrieve all of them coming with the proper assigned companyid Foreign Key. What I have tried to do is the following:
TypedQuery<Company> query = entityManager.createQuery("SELECT c.id, c.name, c.companyProperties " +
"FROM Company as c where c.id = :id", Company.class);
query.setParameter("id", companyId);
Company result = query.getSingleResult();
The error I get is:
java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Problem compiling [SELECT c.id, c.name, c.companyProperties FROM Company as c where c.id = :id]. [21, 40] The state field path 'c.companyProperties' cannot be resolved to a collection type.
org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1616)
org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1636)
com.sun.enterprise.container.common.impl.EntityManagerWrapper.createQuery(EntityManagerWrapper.java:476)
Trying to do it with joins (the furthest point I got was with
Query query = entityManager.createQuery("SELECT c.id, c.name, p " +
"FROM Company c LEFT JOIN c.companyProperties p where c.id = :id");
does not give me either the correct results (it only returns the value of the property and not a list of them with key-value).
How can I define the right query to do this?
Your JPA syntax looks off to me. In your first query you were selecting individual fields in the Company entity. But this isn't how JPA works; when you query you get back the entire object, with which you can access any field you want. I propose the following code instead:
TypedQuery<Company> query = entityManager.createQuery("from Company as c where c.id = :id", Company.class);
query.setParameter("id", companyId);
Company result = query.getSingleResult();
Similarly, for the second join query I suggest the following code:
Query query = entityManager.createQuery("SELECT c" +
"FROM Company c LEFT JOIN c.companyProperties p WHERE c.id = :id");
query.setParameter("id", companyId);
List<Company> companies = query.getResultList();
The reason why only select a Company and not a property entity is that properties would appear as a collection inside the Company class. Assuming a one to many exists between companies and properties, you could access the propeties from each Company entity.
You are expecting to get a complete Company object when doing select only on particular fields, which is not possible. If you really want to save some memory (which in most cases would not be that much of a success) and select only some field, then you should expect a List<Object[]>:
List<Object[]> results = entityManager.createQuery("SELECT c.id, c.name, p " +
"FROM Company c LEFT JOIN c.companyProperties p where c.id = :id")
.setParameter("id", companyId)
.getResultList();
Here the results will contain a single array of the selected fields. You can use getSingleResult, but be aware that it will throw an exception if no results were found.

EclipseLink JPA: list entities with reference variables

I am using JPA's eclipseLink to perform CRUD operations on my entities. I am facing following problem:
I have two tables in DB:
CREATE TABLE User (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(30) NOT NULL UNIQUE,
email VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
signUpDate timestamp NOT NULL DEFAULT NOW()
);
CREATE TABLE Friendship (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
friendsSince timestamp NOT NULL DEFAULT NOW(),
user1_Id INTEGER NOT NULL REFERENCES User(id),
user2_Id INTEGER NOT NULL REFERENCES User(id)
);
The corresponding Entities
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
private String password;
#Temporal(value = TemporalType.DATE)
private Date signUpDate;
// constructors & setters & getters ...
}
#Entity
public class Friendship {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name="user1_Id", referencedColumnName = "id")
private User user1;
#ManyToOne
#JoinColumn(name="user2_Id", referencedColumnName = "id")
private User user2;
#Temporal(value = TemporalType.DATE)
private Date friendsSince;
// constructors & setters & getters ...
}
If I want to retrieve a list of some entities, according to "WHERE" clause of a query I get this "unknown state or association field [user1_Id] of class [com.filip.xxx.Friendship]" error.
Specifically:
I try to build this query:
Query query = mgr.createQuery("select f.id ,f.friendsSince, f.user1_Id, f.user2_Id from Friendship f where f.user1_Id = :user1Id and f.user2_Id = :user2Id or f.user1_Id = :user11Id and f.user2_Id = :user12Id");
and recieve this exception:
java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Error compiling the query [select f.id ,f.friendsSince, f.user1_Id, f.user2_Id from Friendship f where f.user1_Id = :user1Id and f.user2_Id = :user2Id or f.user1_Id = :user11Id and f.user2_Id = :user12Id], line 1, column 31: unknown state or association field [user1_Id] of class [com.filip.xxx.Friendship].
It seems like there is a problem with mapping attributes back to the entities, because I have no problem with persisting these two entities.
And interesting is that, if I run this query:
Query query = mgr.createQuery("select f from Friendship f");
It returns me the correct list of all friendships entities.
Notice that the reference variable's name in friendship entity(user1, user2) are not the same as corresponding table's variables (user1_Id, user2_Id). Before I have used the same variable names in entity as in table, but recieved this error at persisting friendship entity:
javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461):
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'USER1_ID' in 'field list'
Error Code: 1054
Call: INSERT INTO FRIENDSHIP (FRIENDSSINCE, USER1_ID, USER2_ID) VALUES (?, ?, ?)
bind => [3 parameters bound]
Basically I don't understand, why eclipse link renames the entity's reference variables (user1 -> USER1_ID, user2 -> USER2_ID) when creating sql query, when it has than problems to map it back to the entities.
I have already tried these solutions:
Build query and return user1_Id column as user1 and user2_Id as user2
select f.id ,f.friendsSince, f.user1_Id as user1, f.user2_Id as user2 from Friendship f where f.user1_Id = :user1Id and f.user2_Id = :user2Id or f.user1_Id = :user11Id and f.user2_Id = :user12Id
but recieved the same IllegalArgumentException as above.
Could you help me solve this problem ?
Thanks
The exception
unknown state or association field [user1_Id] of class [com.filip.xxx.Friendship]
is received because you are using user1_Id name which is a database column name.
From the other hand ElementManager.createQuery() method expects JPQL string which accepts the entity's field name user1. Try to replace your query string with:
select f.id, f.friendsSince, f.user1, f.user2
from Friendship f
where f.user1 = :user1Id and
f.user2 = :user2Id or
f.user1 = :user11Id and
f.user2 = :user12Id

How to use #Subselect in Hibernate

I am trying to work on an example for #Subselect using Hibernate documentaion.
I have created entities for Bid and Item as follows:
#Entity
public class Bid {
#Id
private int id;
#Column(name="item_id")
private int itemId;
#Column
private int amount;
//getters & setters
}
#Entity
public class Item {
#Id
private int id;
#Column
private String name;
//getters and setters
}
I have inserted some records in database tables for Bid and Item. Now I have created another entity to test the #Subselect as:
#Entity
#Subselect("select item.name name, max(bid.amount) amount, count(*) count " + "from item "
+ "join bid on bid.item_id = item.id " + "group by item.name")
#Synchronize({ "item", "bid" })
// tables impacted
public class Summary {
#Id #GeneratedValue
private int id;
#Column
private String name;
#Column
private String amount;
#Column
private String count;
//getters & setters
}
I am new to Hibernate so trying to create a sample program to test the feature of #Subselect.
public class AppTest {
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
//createItemsAndBids(session);
Summary summary = new Summary();
session.save(summary);
session.getTransaction().commit();
HibernateUtil.getSessionFactory().close();
}
When I run this program I am getting below errors:
Hibernate: select hibernate_sequence.nextval from dual Hibernate:
insert into ( select item.name name, max(bid.amount) amount, count(*)
count from item join bid on bid.item_id = item.id group by item.name )
(amount, count, name, id) values (?, ?, ?, ?) Aug 10, 2014 1:24:31 PM
org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions WARN:
SQL Error: 904, SQLState: 42000 Aug 10, 2014 1:24:31 PM
org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions ERROR:
ORA-00904: "ID": invalid identifier
Caused by: java.sql.SQLSyntaxErrorException: ORA-00904: "ID": invalid
identifier
Please help me how to test the feature of #Subselect of hibernate
Also I tried using HQL, even then I am getting same error:
public class AppTest {
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
//createItemsAndBids(session);
Query query = session.createQuery("from Summary");
List result = query.list();
System.out.println(result);
session.getTransaction().commit();
HibernateUtil.getSessionFactory().close();
}
Update:
The error I am getting with this HQL query is :
Aug 11, 2014 12:35:07 AM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000232: Schema update complete
Hibernate: select summary0_.id as id1_2_, summary0_.amount as amount2_2_, summary0_.count as count3_2_, summary0_.name as name4_2_ from ( select item.name name, max(bid.amount) amount, count(*) count from item join bid on bid.item_id = item.id group by item.name ) summary0_
Aug 11, 2014 12:35:07 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 904, SQLState: 42000
Aug 11, 2014 12:35:07 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: ORA-00904: "SUMMARY0_"."ID": invalid identifier
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:80)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:91)
at org.hibernate.loader.Loader.getResultSet(Loader.java:2065)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1862)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1838)
at org.hibernate.loader.Loader.doQuery(Loader.java:909)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354)
at org.hibernate.loader.Loader.doList(Loader.java:2553)
at org.hibernate.loader.Loader.doList(Loader.java:2539)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2369)
at org.hibernate.loader.Loader.list(Loader.java:2364)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:496)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:387)
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:231)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1264)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)
at org.hibernate.tutorials.hibernate5.one.AppTest.main(AppTest.java:19)
Summary is supposed to be an immutable, read-only entity. It makes no sense to create a Summary. What you can do is create Items, create Bids, then query Summary instances.
EDIT: the error is pretty clear. Look at the generated SQL:
select summary0_.id as id1_2_, summary0_.amount as amount2_2_, summary0_.count as count3_2_, summary0_.name as name4_2_ from ( select item.name name, max(bid.amount) amount, count(*) count from item join bid on bid.item_id = item.id group by item.name ) summary0_
and at the error:
ORA-00904: "SUMMARY0_"."ID": invalid identifier
Your entity defines an id property:
#Id #GeneratedValue
private int id;
but the query of the Subselect annotation doesn't select any property named id:
select item.name name, max(bid.amount) amount, count(*) count from item
join bid on bid.item_id = item.id
group by item.name
You probably want your query to be
select item.id id, item.name name, max(bid.amount) amount, count(*) count from item
join bid on bid.item_id = item.id
group by item.id, item.name
Also note that the #GeneratedValue annotation doesn't make sense, since you can't persist instances of Summary, and Hibernate will thus never have to generate an ID for this entity.

Categories

Resources