The column tests in my database looks like:
set('TEST1','TEST2', 'TEST3', ....)
I am trying to query against multiple values inside the set.
I tried doing the following:
criteria.createAlias("tests", "test");
criteria.add(Restrictions.eq("test", "TEST1"));
but got the following exception:
org.hibernate.QueryException: not an association: tests
Can't figure out how to access values from 'tests' set.
The other way I tried was the following since I need to compare multiple values inside the set but it didn't work either:
Criterion c1 = Restrictions.like("tests", EnumSet.of("TEST1"));
Criterion c2 = Restrictions.like("tests", EnumSet.of("TEST2"));
criteria.add (Restrictions.or(c1, c2));
Consider, you have created criteria as
Criteria criteria = session.createCriteria(TestCriteria.class, "testCriteria");
& TestCriteria class have property named tests. Then you can create alias for the same as
criteria.createAlias("testCriteria.tests", "test");
criteria.add(Restrictions.eq("test", "TEST1"));
From the Hibernate Docs:
Criteria createAlias(String associationPath,
String alias)
throws HibernateException
Join an association, assigning an alias to the joined association.
Functionally equivalent to createAlias(String, String, JoinType ) using
JoinType.INNER_JOIN for the joinType.
Parameters:
associationPath - A dot-seperated property path
alias - The alias to assign to the joined association (for later reference).
Returns:
this (for method chaining)
Throws:
HibernateException - Indicates a problem creating the sub criteria
Hope this helps.
Related
How do we load multiple entities using Hibernate in the order of the list of Pks that is provided to the Hibernate query?
In the code below, the order of the list output is in ascending order rather than the order in which the Pks is supplied in the argument
Criteria criteria = s.createCriteria(entityClass).add(Restrictions.in(idPropertyName, pks));
List list = criteria.list();
You get them, then sort them using a comparator that compares the index of each entity in the list.
For example:
Map<Long, Integer> indexById = new HashMap<>();
for (int i = 0; i < pks.size(); i++) {
indexById.put(pks.get(i), i);
}
List<MyEntity> entities = seachByIds(pks);
entities.sort(Comparator.comparing(entity -> indexById.get(entity.getId())));
As I explained in this article, there are several ways you can achieve this goal.
In your example, you were using the legacy Hibernate Criteria, but since it's been deprecated since Hibernate 4 and will probably be removed in Hibernate 6.
Therefore, it's better to use one of the following alternatives.
Note that, in your example, you have the entity identifier values defined in a pks variable of the List type, and I'm going to reuse that in the examples below as well.
JPQL
You can use a JPQL query like the following one:
List<Book> books = entityManager
.createQuery(
"select b " +
"from Book b " +
"where b.id in (:ids)", Book.class)
.setParameter("ids", pks)
.getResultList();
When using JPQL, The ids parameter will pass the entity identifiers in the same order they were defined in the pks variable.
Criteria API
If you want to build the query dynamically, then you can use a Criteria API query:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Book> query = builder.createQuery(Book.class);
ParameterExpression<List> ids = builder.parameter(List.class);
Root<Book> root = query
.from(Book.class);
query
.where(
root.get("id").in(
ids
)
);
List<Book> books = entityManager
.createQuery(query)
.setParameter(ids, pks)
.getResultList();
When using Criteria API, The ids parameter will pass the entity identifiers in the same order they were defined in the pks variable.
Hibernate-specific multiLoad
List<Book> books = entityManager
.unwrap(Session.class)
.byMultipleIds(Book.class)
.multiLoad(pks);
By default, the Hibernate multiLoad, The ids parameter will pass the entity identifiers in the same order they were defined in the pks variable. Only if you called enableOrderedReturn(false) explicitly, then the result set will not be ordered.
Now, the JPQL and Criteria API can benefit from the hibernate.query.in_clause_parameter_padding optimization as well, which allows you to increase the SQL statement caching mechanism.
For more details about loading multiple entities by their identifier, check out this article.
I need to retrieve all primary keys of a table and put them in a list.
Any method that I have found so far let me retrieve each record as an object, which force me to retrieve their primary keys separately and add them to the list.
Is there any other approach to retrieve the primary keys of a table and adding them to a list?
Using the following code hibernate returns objects but I need it to return a list of primary keys to store them in pk list.
List pk = new ArrayList():
Criteria criteria = session.createCriteria(MyTable.class, "mytable");
pk = criteria.list();
if mytable is as following
id name value
1 a z4
2 f o2
pk list should be
[1,2]
You can simply create an HQL query that returns the field you want:
session.createQuery("SELECT mt.id FROM MyTable mt").list();
assuming your primary key field is named id and MyTable is your entity. You can also do it with Criteria and Projections.
There are generally there ways to achieve that
1) Using Criteria API
2) Using HQL
3) Using Native Query
From the above hibernate queries way , better to us (1) and (2) , the 3rd way has dependency on the type of database.
1) Using Criteria API
Criteria criteria = session.createCriteria(MyTable.class, "mytable");
criteria.setProjection( Projections.projectionList().add( Projections.property("mytable.id"), "mytable.id"));
List<Long> ids=criteria.list();
2) Using HQL
Solution is already explained by Sotirious
3) Using Native Query
session.createSQLQuery(" SELECT mytable.id FROM MyTable mytable ").addScalar("ID","Hibernate.LONG").list();
Another approach is to use finder queries directly on repository(Spring JpaRepository) methods.
public interface MyRepository extends JpaRepository<MyTable, KeyType> {
#Query("select mt.id from MyTable mt")
List<KeyType> getAllIds();
}
My query is:
List<EmpModel> EmpData = sess2.createCriteria(EmpModel.class)
.setFetchMode("TestModel", FetchMode.JOIN)
.add(Property.forName("id").in(emp_ids)).list();
Now, the query fired is completely correct. It returns a one-to-one join of the test and emp tables. However, The returned print statement only gives me the values from the EmpModel table. I believe the reason for this is that the emp_ids mentioned above always comes up as zero for which every value in the test table is null. Can someone tell me how to get over this error?
If you want the criteria to return TestModel instances also, you can add another criteria and and a result transformer. You didn't post your entities, so if for example EmpModel has a property testModel:
List<<HashMap<String, Object>> EmpData = sess2.createCriteria(EmpModel.class)
.add(Property.forName("id").in(emp_ids))
.createAlias("testModel", "tm")
.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
.list();
Notice that the return type is changed from List<EmpModel> to List<<HashMap<String, Object>>, because now the query will return a list of HashMaps. Each HashMap will have a "this" entry pointing to a EmpModel, and a "tm" entry (the alias we assigned when building the query) pointing to the corresponding TestModel.
PS: I removed the setFetchMode from the code. Somehow that doesn't work with the above approach.
Suppose I create a Criteria using Hibernate:
Session session = (Session) entityManager.getDelegate();
Criteria rootCriteria = session.createCriteria(entityClass);
If I do not set an alias explicitly Hibernate will use "this" as an alias (I checked out and it is hardcoded into the CriteriaImpl class.
If I create a subcriteria for this one:
Criteria subCriteria = rootCriteria.createCriteria(associationPath, CriteriaSpecification.LEFT_JOIN);
Hibernate creates an instance of Subcriteria which is an inner class of CriteriaImpl and it does not assign an alias to it in the process.
If I run the query however and check my SQL log I can see that Hibernate created an alias for it but only when I ran the query. Since I want to add Restrictions to my query using this Subcriteria it would be nice if I had an alias generated for me. Is there a way to make Hibernate generate that alias or I'll have to pass them to the factory methods?
normally createCriteria is used when chaining restrictions without the need to use aliases
Criteria crit = session.createCriteria(Order.class)
.createCriteria("Items")
.add(Restrictions.gt("count", 1))
.add(Restrictions.gt("price", 10))
.list();
will generate
SELECT * FROM orders o join items i ON ... WHERE i.count > 1 and i.price > 10
with alias it looks like
Criteria crit = session.createCriteria(Order.class)
.createAlias("Items", "item")
.add(Restrictions.gt("item.count", 1))
.add(Restrictions.gt("item.price", 10))
.list();
I'm using jpa 2.0 and I have the following entity:
#Entity
public class Folder{
#ElementCollection
#CollectionTable(name="folder_files")
private Set<String> files;
// .....
}
Given a file name, I would like to delete all entries where files == theGivenFileName. In sql it would be something like this:
Delete from folder_files where files = XXX
Is there a way to perform this query using criteria-api?
If not, is there a way to perform this query using jpql?
UPDATE:
I think my question was not clear enough:
Since jpql uses entities (and not tables) I cannot just perform the sql written above plus since I'm using #ElementCollection I don't know how to address this variablr or even deal with it. I would like to delete all entries in that collection (in my case, the files set) which holds a given value, from all entities. Is that possible using jpql or (even better) criteria-api?
The Delete FROM clause requires an Entity, so there is no way to delete from an element collection from what I understand.
You can use a native SQL query, or you can map the element collection as a OneToMany to an Entity instead.
You can use the like query just the syntax is slightly changed.
query = em.createQuery("SELECT i FROM Item i WHERE UPPER(i.name) LIKE :keyword ");
query.setParameter("keyword", "%" + keyword.toUpperCase() + "%");
You can read more on following link,
https://forums.oracle.com/forums/thread.jspa?threadID=423742
Updated:
#Noam you can do it: Like in Criteria API
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();
Kindly read more on it at following link:
http://ctpconsulting.github.com/query/1.0.0.Alpha3/criteria.html
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html
This cannot be done. Via JPQL it does not work because DELETE statement can only be applied to entities. Excerpt from JPA 2.0 specification:
Bulk update and delete operations apply to entities of a single entity
class (together with its subclasses,if any).
...
delete_statement ::= delete_clause [where_clause]
delete_clause ::= DELETE FROM entity_name [[AS] identification_variable]
Also it doesn't work via Criteria API. CriteriaQuery supports only selecting - not updates or removals.
You have to go for native SQL.