I have the following Entities (reduced and renamed for this example)
#Entity
public class Case {
#Id
private Long id;
#ManyToOne(optional=false)
private CourtConfiguration courtConfiguration;
#ElementCollection(fetch=FetchType.EAGER)
private List<String> caseNumbers;
}
Second Entity
#Entity
public class CourtConfiguration {
#Id
private Long id;
String countyId;
String referenceId;
....
}
I am trying to search using JPQL for all Cases that have a certain courtConfiguration countyId and have caseNumbers containing all of a provided set of important caseNumbers.
So my query needs the countyId and set of caseNumbers as parameters. Called countyId and importantCaseNumbers respectively.
I have tried and failed to get it to work.
My query looks like this
String query = "SELECT case FROM Case case JOIN case.caseNumbers caseNumbers WHERE ";
query += "case.caseConfiguration.countyId = :countyId ";
The bit above works until I add my caseNumber conditions.
I have tried a foreach importantNumbers to extend the query and as soon as the list of important numbers goes above one it doesn't work. No values get returned.
for (String importantCaseNum : importantCaseNumbers) {
query += " AND '"+importantCaseNum+"' in (caseNumbers)";
}
Any suggestions/pointers appreciated. I guess what I am looking for is a case.caseNumbers contains (importantNumbers) clause.
Update I have reverted to native SQL for my query as I didn't want to tie myself into hibernate by using HQL. Thanks to #soulcheck and #mikko for helping me out. I'll post up when the hibernate JPA fix is available.
Thanks
Paul
Syntactically correct way to build this JPQL query is with MEMBER OF. But because of problem reported in HHH-5209 it doesn't work with old Hibernate versions (fix version 4.1.8, 4.3.0.Beta1). According bug report HQL version of this query works, so your options includes at least:
Using JPQL query and switching to some other JPA implementation
Using HQL instead and sticking with Hibernate:
query += " AND '"+importantCaseNum+"' in elements(caseNumbers)";
Related
Say I have the following Entity classes:
#Entity public class MyEntity {
#Id private String id;
#ManyToOne private MyOtherEntity myOtherEntity;
}
#Entity public class MyOtherEntity {
#Id private String id;
#Column private String name;
}
Now I want to do a query to get all the MyEntitys linked to a certain MyOtherEntity, I wonder the difference between the following 3 predicates:
cb.equal(root.get(MyEntity_.myOtherEntity), myOtherEntity);
cb.equal(root.get(MyEntity_.myOtherEntity).get(MyOtherEntity_.id), myOtherEntity.getId());
cb.equal(root.get(MyEntity_.myOtherEntity).get(MyOtherEntity_.name), myOtherEntity.getName());
How would the generated SQLs look like in each case? And which one is most efficient?
For a start I suggest to take the trouble and enable SQL logging in Hibernate while developing - see here. Knowing the exact statements Hibernate creates for your JPA queries is invaluable, e.g. you have a chance to spot N+1 query problems, excessive joins etc.
Having said that, in your case the statements should look like as follows:
cb.equal(root.get(MyEntity_.myOtherEntity), myOtherEntity) → SELECT ... FROM MyEntity WHERE MyEntity.myOtherEntity_id = ?. In cases like this, Hibernate usually knows to optimize and avoid the unnecessary join.
cb.equal(root.get(MyEntity_.myOtherEntity).get(MyOtherEntity_.id), myOtherEntity.getId()) → Should be like above; again Hibernate should know that the .get(MyOtherEntity_.id) is already in the table and avoid the unnecessay join.
I have seen Hibernate working the way I describe for the cases above. Definitely enable SQL logging to verify, there may be details for your own use case that make it behave in a different way!
cb.equal(root.get(MyEntity_.myOtherEntity).get(MyOtherEntity_.name), myOtherEntity.getName()) → Will definitely create a join because it cannot find myOtherEntity.name in the MyEntity table: SELECT ... FROM MyEntity e JOIN MyOtherEntity oe ON ... WHERE oe.name = ?
I'm trying to do an insert into select with Jpa.
The Entity on which I try to do it is like this:
#Entity
public class A {
private String fieldOne;
private String fieldTwo;
private String fieldThree;
private B fieldFour;
#Id
public String getFieldOne(){...}
#Id
public String getFieldTwo(){...}
#Id
#OneToOne
public B getFieldThree(){...}
public String getFieldFour(){...}
....
#Entity
public class B {
private CompositeId id;
....
#EmbeddedId
public CompositeId getId(){
return MyUUIDGenerator.generateCompositeId();
}
....
The insert I'm trying to is very simple:
insert into A (fieldOne, fieldTwo, fieldThree, fieldFour)
select 'staticValueOne', 'staticValueTwo', B.id, 'staticValueFour' from B
where ....
The 'staticValueX' are values calculated by the application that I need to be all equals for a given set of B elements.
During execution the application return the exception:
java.lang.IllegalArgumentException: org.hibernate.QueryException: can
only generate ids as part of bulk insert with either sequence or
post-insert style generators [insert into ...
I don't understand why, because I don't have any generated value in A, I give to the insert all the values it need.
Does anyone has a suggestion to understand this behaviour?
Thanks!
EDIT: a little update...
I changed the class A with only a field of String type marked as #Id, but hibernate makes errors in building correctly the query: the association of tables alias with fields name miss some fields.
From JPA 2.0 specification, chapter 4.2 Statement Types:
A Java Persistence query language statement may be either a select
statement, an update statement, or a delete statement. (...)
In BNF syntax, a query language statement is defined as:
QL_statement :: = select_statement | update_statement | delete_statement
Instead of SELECT statement which is not supported in JPA (either in JPQL or Criteria API) use ElementManager.persist on an entity within a transaction. When transaction commits the entity is written to the database (SQL INSERT will be done implicitly by Hibernate which acts as the persistence provider).
EDIT: In case of a large number of insertions you may take a closer look at Hibernate's batch inserts. Another option is to give up with JPA and use JDBC's batch insertion (PreparedStatement) directly.
Hello all and sorry for my English =)
I works with Hibernate using criteria API. Everything was fine, but I have several denormalized tables with data for reports, and I faced some troubles.
For one of that tables I created #Entity class for mapping like
#Entity
#Table(name= "table")
public class Report {
#Id
Integer id;
Integer product_id;
Integer warehouse_id;
String some_data;
}
with simple queries all works fine. But I need to make queries like pivot table or self join etc.
for example
select
t1.product_id,
t2.warehouse_id
from repost t1
join report t2
on t1.product_id = t2.product_id
and t1.warehoise_id = ?
where t1.some_data in (?)
Such query does not contain logical dependencies between entities like Primary_Key - Foreign_Key and can return custom object data (it can be Map<>, List<>, Pair<>, Long...)
Is it possible to make query like this without using HQL?
Thanks
ADDED
As I was understood it's not possible using HQL too
I've the following hibernate entities
public class Container {
...
#OneToMany
private List<ACLEntry> aclEntries;
}
For securing my container instances i use the following entity:
public class ACLEntry {
...
private Long sid;
private boolean principal;
private Integer mask;
}
The hql-queries will be created automatically so for searching container instances,
the following query will be created:
select container from Container container
inner join container.aclEntries as aclEntry
with bitwise_and (aclEntry.mask, 1) = 1 and
(aclEntry.sid = :userId or aclEntry.sid = :roleId)
The problem with this is, that the aclentry join could return 2 results which will result in duplicate container results.
Has anyone an idea how to solve this ?
As far as I understood the problem you need a container that can hold multiple entries of your Container object just replace your hql query with the following one:
With adding select distinct as native query.
As a brute force solution, you could write a native query.
It might make more sense to write this as a Criteria query, which easily supports selecting an object based on conditions of it's associations.
The same thing can be done in HQL or a native query, it might be instructive to execute a Criteria query specifying the same logic and just see what HQL/SQL it generates.
What is the right way do validate a jpa query programmatically. Hibernate validates all annotation based named queries on entities. But how can I call this validation routine on programmatically builded jpa queries, to check for errors?
#Entity
public class Foo {
#Id
public int id;
public String name;
}
main(...) {
Query q = getEntityManager().createQuery("select e from " + Foo.class.getName() + " e where e.name = 'x' ");
// validate q here
}
Don't. Integration test the hell out of your code, using a real database with the same schema as your production environment.
Think about it: if you create a malformed query, that's a programming bug. What are you going to do with the information? Tell the user that a JPA query is malformed? All you can realistically do is log the error and tell the user "something bad happened". You'll know it's a malformed query when you check the logs later anyway...
Edit
It might also be worth investigating the createQuery() call by feeding it bad data - the javadoc here suggests that it can throw a HibernateException, and I'm not sure what it could do with a string other than validate it...
Either you can use createQuery, or you need to put your class name while writing a JPQL.