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.
Related
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
I have 2 tables in MySQL database: user and user_additional_details with columns described below.
User
id (auto increment)
userId (unique)
first name
last name
phone
email
User Additional Details
id (auto increment)
userId (matches userId in User)
personalPhone
personalEmail
Table user_additional_details contains 0 or 1 row for each userId in user table.
However, database does not have a foreign key constraint defined. Ideally, columns from user_additional_details should have been added as nullable columns in user table, but that was not done for some unknown reason. Now I need to define the entity for following query.
select user.userId, user.phone, user_a_d.personalPhone
from user
join user_additional_details as user_a_d
on user.userId = user_additional_details.userId
I tried defining JPA entities for the tables, but not able to figure out how to create an entity that uses columns from different tables.
It seems like the SecondaryTable annotation is what you are looking for
Specifies a secondary table for the annotated entity class. Specifying
one or more secondary tables indicates that the data for the entity
class is stored across multiple tables.
Here you find a detailed example of how to use it - http://www.thejavageek.com/2014/09/18/jpa-secondarytable-annotation-example/
Create UserEntity (with all the columns from User table) and UserAdditionalDetailsEntity(with all the columns from user_additional_details table). I assume you are aware how to create JPA entities and map them to database table.
I hope you would have create entity manager factory object in your spring configuration file. With the help of that create entity manager object .
Once EntutyManager Object is created:
Query q= em.createQuery("select user.userId, user.phone, userDetails.personalPhone
from UserEntity user
join UserAdditionalDetailsEntity as userDetails
on user.userId = userDetails.userId");
List<Object[]> resultList= q.getResultList();
Once you get resultList you can iterate over the list of object array and get data.
Each index of the resultList will contain the object array representing one row
Keep in mind that field name mentioned in query should be same as the one mentioned in your JPA Entites.
I would like to do the following query using spring jpa. I am able to build the where clause for my statement with Predicate.toPredicate. However, I don't know how to join on more than one column. On a single column it can be done in the repository using #Query and #Param
SELECT a.name, a.column_x, b.column_y
FROM table_a a
INNER JOIN table_b b
ON b.name = a.name
AND b.pk_2 = a.pk_2
AND b.pk_3 = a.pk_3
WHERE ...;
Another question I have is, is an intermediate tableA_tableB association beneficial if I have something like this, oneToMany relations.
Table 1: thing
thing_name
type
tenant
other1
other2
Table 2: thing_sub_prop
prop_name
value
Association table: thing_thing_sub_prop
type
thing_name
tenant
prop_name
value
Or is it better to just have two tables, thing and thing_sub_prop with the primary key columns of thing repeated in thing_sub_prop as a foreign key?
I'm trying to create "search engine" on my DB.
I have a table with Id, Name and Description.
When I have an Id I can get the record with this Id by find().
But if I want to get records by Name or Description how can I do that? Did I've to set the Name as index?
Thanks.
As a general rule, if you have to frequently query a table by one of its fields and the table contains many records, it might be a good idea to create an index for that field in the database.
About the other question: if you need to get records by name, by description or by some other field and you're using JPA, then use the JPQL query language. For example, assuming that the entity is of type MyEntity (with fields id, name, description) the following query will return a list of entities with name aName:
EntityManager em = ... // get the entity manager
Query q = em.createQuery("SELECT me FROM MyEntity me WHERE me.name = :name");
q.setParameter("name", aName); // aName is the name you're looking for
List<MyEntity> results = (List<MyEntity>) q.getResultList();
Read more about the Java Persistence API in the tutorial.
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