What is Empty in JPA? - java

I create a customer table and for the column called as loan
I pass null for 1 row
I pass '' for another row
and when I execute this query
SELECT c FROM Customer c WHERE c.loans IS EMPTY
I get nothing.

The IS EMPTY operator is the logical equivalent of IS NULL, but for collections.
Queries can use IS EMPTY operator or IS NOT EMPTY to check whether a collection association path resolves to an empty collection or has at least one value.
We can use the EMPTY to check if a property is empty.
The following JPQL shows how to use EMPTY to get employee withno projects.
Query unassignedQuery =
em.createQuery("SELECT e " +
"FROM Employee e " +
"WHERE e.projects IS EMPTY");
According to the JPA 2.1 spec:
If there are no associated entities for a multi-valued relationship of
an entity fetched from the database, the persistence provider is
responsible for returning an empty collection as the value of the
relationship.
Reference

Related

JPA custom query returning List of nulls

I have the following JPA query
#Query("SELECT a, b, c, d FROM table WHERE a in (:ids)", native = true)
List<Row> getRowByIDs(#Param("ids") List<String> ids);
Row class has same mapped fields a,b,c,d from the query
When there is no matched rows from the query in the DB
it strangely returns a non null List but with one or more null items
When I print the result returned from java I get this
[null, null]
I have another similar api which returns empty list [] correctly
So I assume it is a problem with some mapping and/or db fields not matching?
Please help
I found out that the #Id was on the wrong attribute.
It looks like that spring jpa will return List with null elements for each record where the attribute annotated by #Id returned from the query is null
even if your where clause is on a non-key attribute

Hibernate Criteria query for a Set column

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.

"SELECT *" into a hibernate entity, without populating any relationships / join table data

I'm looking to load data into a hibernate entity by running something like select * from <table> where id = ?. I'm only interested in the data sitting in <table> -- no joins whatsoever.
I can achieve this by using the following:
T result = (T) getSession()
.createSQLQuery("SELECT * FROM " + tableName + " WHERE " + idColumn + " = ?")
.setInteger(0, id)
.setResultTransformer(new AliasToBeanResultTransformer(type))
.uniqueResult();
But this only works for entities that don't have relationships. For any entity with a relationship to another, i get a PropertyNotFoundException when the result transformer is trying to set some <relationshipName>_id property on my entity (eg. org.hibernate.PropertyNotFoundException: Could not find setter for administration_id on class com.xxxxxx.xxxx.model.AdministrationPIN
Are there any other transformers that could automatically handle this. Or possibly some sort of object binder that could be used from an entity map, if I was to use the Criteria.ALIAS_TO_ENTITY_MAP result transformer instead?
Update
It's important that all of the data sitting in the table is loaded into the entity, including the relationship data. So if entity A has a OneToOne with entity B, and I load entity A using this method, a.getB() should return an instance of B, but the B instance should only be populated with its identifier.

Hibernate handle long 0 value instead of NULL in ManyToOne relations

I use Hibernate to access to a legacy DB. For some tables the parent-child reference integrity is not enforced, and the long 0 value is used instead of NULL for some "parent" columns in child tables to denote "no parent".
I still want to use these relations in #ManyToOne and #OneToMany fields, but get EntityNotFound error since the 0 value does not correspond to any record in master table.
What are my options?
Use the NotFound annotation:
#NotFound(action = NotFoundAction.IGNORE)
See http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-manytoone
Instead of the #JoinColumn could be used #JoinFormula. Like this
#JoinFormula(value="CASE the0isNullColumn"
+ " WHEN 0"
+ " THEN NULL"
+ " ELSE the0isNullColumn"
+ " END")
The expression means we check the column and if it's 0 return NULL. Then hibernate doesn't search for the related entity.
You can map it to java.lang.Long which default value is null. Or you can use a #PostLoad and null it if 0. You can also use a #Formula and ignore 0.
The #Formula as written in their documentation can be used to join conditions.
Since I don't know your data model providing a valid example is tricky. Try with:
id_fk is not null or id_fk <> 0
block.
If it does not suit your needs you can write you own Query loader
If you are using some sort of logging enable the show_sql property. And add to your config the org.hibernate.sql DEBUG.

How to add property counted in DB to #Entity class?

I have an Entity. And sometimes I need this object also contains some value, call it 'depth'. The query may look like 'select b.id, b.name, b..., count(c.id) as depth from Entity b, CEntity c where ...'. So I've created class NonHibernateEntity which extends Entity. And then results of query written above are perfectly stored as List of NonHibEntity, which consists of all the fields of Entity (as they are extended), and property 'depth'. I make it by setting aliasToBean results transformer: .setResultTransformer(Transformers.aliasToBean(NHEntity.class)).
But, it is annoying and inconvenient - to specify all the aliases of all the needed fields.
And then, if I want to save one of this object to DB - session.saveOrUpdate((Enity)nHibEntity) - there are an exception about nHibEntity isn't Hibernate Entity.
I heard about storing 'entity' as field in NonHibEntity (aggregation, not inheritance). But it seems this is rather inconvenient too.
What do you think? What is an appropriate solution?
A Formula column mapping may be suitable for your needs. I would try this first.
If this causes performance issues as you fear, you might try a mapped class hierarchy with this field only in the child, and mapping both to the same table. Not sure this will actually work though...
As a last resort, do what you've got now using a non-mapped class, but with the entity as a field in your other class - aggregation instead of inheritance as you say, and make sure there's a way of retrieving the mapped entity from the unmapped one so that you can save. It be sensible to make it a Decorator, so that it's both a subclass and aggregate and you can continue to ignore the distinction in much of your code.
With the non-mapped subclass and/or aggregate, however, you'll have to pull out the entity in order to save.
If somebody want to know - I solved this problem in such way:
just made this calculated field as #Transient, and then
List<BaseEntry> result = new ArrayList<BaseEntry>();
Iterator it = session()
.createQuery("select b, (select count(p.id) as depth from BaseEntry p " +
" where ... ) as d" +
" from BaseEntry b " +
" where ... ")
.list().iterator();
while ( it.hasNext() ) {
Object[] row = (Object[]) it.next();
BaseEntry entry = (BaseEntry) row[0];
Long d = (Long) row[1];
entry.setD(d);
result.add(entry);
}
return result;
It works good, and seems that it can be easily supported in future

Categories