I want to retrieve some information from Oracle database.
The following query provides me with the required result:
select pl.*
from PEOPLE pl
INNER JOIN ANIMALS c on pl.ID = c.PEOPLE_FK
where c.ID=(select HEALTH_RES.ANIMALS_FK
FROM HEALTH_RES
WHERE HEALTH_RES='1234');
Explanation: each person may have many animals, each animal has only one health result. I want to find owner (all information about him) of animal by id of health result.
Now I have Entities mapped in java, and I want to use a HQL query to obtain such information, how would such query look in HQL?
I have tried this:
select pl from PeopleEntity as pl inner join pl.animals as c where c.Id=(select HealthResEntity.animals_FK FROM HealthResEntity WHERE HealthResEntity.id=:idParam)
But it seem to not work, what is wrong with this query?
EDIT: I am getting null pointer exception when calling method that converts Entity object to domain object which means no data was retrieved
Related
The case is:
I have a repository and two methods, one of them looks like:
//There is no warning about: Activity domain type or valid projection interface expected here...
#Query("select distinct a.creatorId from Activity a")
Optional<List<String>> findAllCreatorIds();
The second method looks like:
//There i have warning about: Activity domain type or valid projection interface expected here
#Query("select distinct a.creatorId from Activity a join a.categories c where c.name in ?1")
Optional<List<String>> findAllCreatorIdsByCategoryNames(Set<String> categoryNames);
It looks workable and tests are passed and the generated query is the following:
SELECT DISTINCT activity0_.created_by AS col_0_0_
FROM activities activity0_
INNER JOIN category_item categories1_ ON
activity0_.id=categories1_.activity_id
INNER JOIN categories category2_ ON
categories1_.category_id=category2_.id
WHERE category2_.name IN (?)
I have made the changes to use projection interface. The simple projection interface is:
public interface CreatorIdProjection {
String getCreatorId();
}
The query was changed:
#Query("select a from Activity a join a.categories c where c.name in ?1")
Optional<List<CreatorIdProjection>> findAllCreatorIdsByCategoryNames(Set<String> categoryNames);
Works too. And here is the generated query:
SELECT activity0_.id AS id1_0_,
activity0_.price AS price2_0_,
activity0_.created_by AS created_3_0_,
activity0_.expiration_date AS expirati4_0_,
activity0_.insertts AS insertts5_0_,
activity0_.name AS name6_0_,
activity0_.start_date AS start_da7_0_,
activity0_.updatets AS updatets8_0_
FROM activities activity0_
INNER JOIN category_item categories1_ ON activity0_.id=categories1_.activity_id
INNER JOIN categories category2_ ON categories1_.category_id=category2_.id
WHERE category2_.name IN (?)
I have a few questions related to this case:
Why there is no warning for the first method ?
Why the query have a lot of fields after SELECT when we use
projection? (to be more precise - why we cannot use "select
a.creatorId from Activity a...")
What is the reason of the warning "...domain type or valid
projection interface expected here" if as a result we have a query
that querying the table data instead of what we need.
The warning comes because you're using 'By' in your method name which triggers Spring Data to use (magic) Query methods.
Remove 'By' or replace it with 'Using' or something else and the warning will disappear.
See also https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.details
About question #1:
Why there is no warning for the first method?
There is no Spring Data Projection involved here. You just execute a query returning a list of scalar values, that then is past on (and wrapped in an Optional) by Spring Data. Therefore you should not get such a warning. As a matter of fact I couldn't reproduce the warning at all, nor could I find it in the source code and in any case, the same argument holds for the second method. If it actually produces such a warning please submit a bug.
For question #2a
Why the query have a lot of fields after SELECT when we use projection?
You specify the query exactly using the #Query annotation, and it gets executed as such. Spring Data does not parse your query and removes unnecessary parts, which would be a huge amount of effort for little effect since you provided the query in the first place you might as well provide one that fits your needs.
For question #2b
why we cannot use select a.creatorId from Activity a...?
You can (almost). You just have to specify aliases because JPA will otherwise mangle the column names and Spring Data wouldn't know what columns it is looking at. It actually tells you so when you don't specify aliases. You should get an exception No aliases found in result tuple! Make sure your query defines aliases!. So this should work:
select a.creatorId as creatorId from Activity a...
An alternative is to actually invoke the constructor of a class in the statement:
#Query("select new my.super.cool.projection.CreatorId(a.creatorId)")
Both variants will only query the columns specified.
For question #3
What is the reason for the warning ...domain type or valid projection interface expected here if as a result we have a query that querying the table data instead of what we need.
I was not able to reproduce the warning. I also searched the source code and couldn't find it, so I can't answer this one.
I am new to JPA. I am currently using JPA2.0 in WAS 8.5.5
I have a search screen where we have lot of search criteria's. Now, I have to create Query in JPA such a way that any criteria user has selected, it automatically check for that particular column in DB.
I am not able to find any solution on that. It seems to me that for every search criteria, I have to write new named Query.
Any suggestion or pointers will be appreciated.
You could do it in named query, but you would have to check every single possible criteria if it is null in order to avoid null values affect the results. Beware of unnecessary inner joins, each nullable relation should be included as left join
select e from Employee e left join e.department d
where (:name is null or e.name = :name)
and (:email is null or e.email = :email)
and (:deptId is null or d.id = :deptId)
...
However, depending on complexity of possible combinations, better option could be to not use named queries, but dynamically construct a JPQL depending on selected criteria.
I've got a Player Object in which there is a Collection<Stock>. I'm willing to write a hibernate query which returns the list of players who have a specific stock (for example stock.symbol="**").
any ideas?
No problem use HQL with join syntax.
see it here
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/queryhql.html#queryhql-joins-forms
For example:
Player p join p.myStocks stock where stock.symbol = :symbol
So, I have a rather complex query I am trying to make using the Hibernate Criteria API. I have the following entity classes:
Code
Gift
GiftVendor
GiftVendorStatus
with the following relationships:
Code 1<>1 Gift
Gift 1<>* GiftVendor
GiftVendor 1<>1 GiftVendorStatus
I need to build a Criteria query that returns a List of Code objects, but that restricts it to only Codes that have a Gift that have at least one GiftVendor with a GiftVendorStatus of Online. Here is the code I am using to build the criteria:
Criteria base = CodeDao.getBaseCriteria();
base.createAlias("gift","gift");
base.createAlias("gift.giftVendor","giftVendor");
base.createAlias("giftVendor.giftVendorStatus","giftVendorStatus");
base.add(Restrictions.like("giftVendorStatus.description", "Online%"));
return base.list();
This gives me a List of Code objects, restricted as I would expect. However, it also does additional queries to build out all of the unused relationships of the Gift object, even though I have all of the mappings set up with a fetch mode of Lazy. This results in 4 additional, separate queries for each of my 10000+ results.
I have code to do the query using HQL that works as expected:
String hql = "select c FROM Code c inner join c.gift g inner join g.giftVendors gv inner join gv.giftVendorStatus gvs" +
" WHERE gvs.description like :desc";
HashMap<String,Object> params = new HashMap<String, Object>();
params.put("desc", "Online%");
return performQuery(hql, params);
That code gives me a List of Code objects, as expected, without doing all of the extra queries to populate the Gift object. How do I tell Hibernate not to do those extra queries with the Criteria API?
UPDATE: The problem here is not the retrieval of the Gift table, but rather unrelated one-to-one relationships from the Gift table. For example, Gift has a one-to-one relationship to GiftCommentAggregateCache. This table is in no way related to this particular query, so I would expect lazy initialization rules to apply, and the query to GiftCommentAggregateCache to not occur unless a read is attempted. However, with the Criteria query written out as above, it makes that separate query to populate the model object for GiftCommentAggregateCache.
If I use:
base.setFetchMode("gift.giftCommentAggregateCache", FetchMode.JOIN);
then I do not have any problems. However, that means that in order for this to work as I would expect, I need to add that line for every single unused one-to-one relationship that Gift has. Any ideas as to why the Lazy rules specified in the mappings are not coming into play here?
There are a few different things I have tried:
base.setFetchMode("gift", FetchMode.LAZY); // Still does additional queries
and
base.setFetchMode("gift", FetchMode.SELECT); // Still does additional queries
and
base.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); // Still does additional queries
and
base.setResultTransformer(Criteria.ROOT_ENTITY); // Still does additional queries
and
base.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); // Still does additional queries
and
base.setProjection(Projections.property("gift")); // Does not do additional queries, but incorrectly returns a List of Gift objects, instead of a List of Code objects
From the Hibernate documentation:
Join fetching: Hibernate retrieves the associated instance or collection in the same SELECT, using an OUTER JOIN.
In other words, try using base.setFetchMode("gift", FetchMode.JOIN)
I hope that helps.
Cheers
I need to combine 2 tables using hql, both are having common column, but table1 common column is integer and table2 common column is String
For example,
select a.id as id,a.name as name,b.address as address
from Personal as a,Home as b
where a.id=b.studid
Here a.id is an integer while b.stduid is a string, but Data of both columns is the same.
How can I get the result of the query using hql query?
HQL supports CAST (if underlying database supports it), you can use it:
select a.id as id,a.name as name,b.address as address
from Personal as a,Home as b
where cast(a.id as string) = b.studid
See also:
16.10. Expressions
You really need to think why have you got a need to join two entities by properties of different types. Most likely it suggests that some of the entities need to be refactored, which could include changing data types for columns of the underlying db tables. If the model is correct there will be no need to twist Hibernate.
I had to cast it to String like so :
#Query( value = "select new com.api.models.DResultStatus("+
"cast(ds.demoId as java.lang.String),cast(ds.comp as java.lang.String),cast(ds.dc as java.lang.String),cast(be.buildUrl as java.lang.String)")
Just noticed that you are using JPA, there you can not cast or convert datatpes. In the query language, only values of the same type can be compared! read in http://download.oracle.com/javaee/5/tutorial/doc/bnbuf.html#bnbvu