Hibernate Select distinct with order by another table - java

I know there are many topics around this, but I can't find a solution to my problem. I know if I use "distinct" and "order by" with hibernate, the column from the order by has to be in the select clause. The other articles just say that the column must be in select, but I haven't found an example how this is possible to achieve.
This is my Class:
#Entity
#Table(name = "DANCE")
public class Dance implements Serializable {
#Id
private int tanzid;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SID")
private School school;
#Basic
#Column(name = "titel")
private String titel;
(getter setter...)
My (not working) query:
SELECT distinct d FROM Dance d order by d.school.schoolname
If I do order by title for example it is working.
I have tried to set the schoolname in the select clause:
SELECT distinct d, d.school.schoolname FROM Dance d order by d.school.schoolname
but then hibernate is complaining that the return type of the query isn't from type "Dance.class"
How can I achieve an order by schoolname.
Thank you

You would have to select distinct rows with regard to one column. This is unfortunately not the part of sql standard, so in jpql or hql this cannot be done. You would have to use vendor - specific syntax and native query to achieve this. Here is an example in postgres.

Related

Differences between JPA predicate using Entity and property

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 = ?

Mapping hierarchical data in Hibernate

In a Hibernate application I'm working on a table with hierarchical data (Oracle Database).
For the sake of simplicity I'll put an example of a person with a father (assume the hierarchy is not fixed and can extend for more than 3 levels).
Every Person may own a couple of Cars.
#Entity
class Person
{
#Id
private String id;
#ManyToOne
#JoinColumn(name = "FATHER_ID")
private Person father;
}
#Entity
class Car
{
#Id
private String id;
#ManyToOne
private Person owner;
}
So far whenever we needed to fetch all cars for a person's descendants, we issued a native query fetching all descendants' ids and then a second hql query to fetch the cars themselves (using IN clause with the previously fetched ids as bind parameters).
I don't like it because it stains our code and causing us to issue more queries than we actually need.
Moreover, we are kind of abusing the IN clause, using a different number of bind parameters for many of our queries.
So I decided to try and encapsulate this hierarchical data using Hibernate.
I've tried using #JoinFormula to get the person's descendants as a data member like this:
#Entity
class Person
{
...
#JoinFormula(value = "SELECT p.id FROM Person p START WITH p.id = id CONNECT BY PRIOR p.id = father_id", referencedColumnName = "id")
#OneToMany
List<Person> descendants;
}
Unfortunately it doesn't work, hibernate throws an exception:
ClassCastException: org.hibernate.mapping.Formula cannot be cast to org.hibernate.mapping.Column
I have tried changing the relation to #ManyToMany, it fixes the ClassCastException, but then hibernate just ignores the formula and creates a new table.
Now I'm thinking of using an sql function to retrieve descendants ids and using it inside my hql.
However I'm not quite sure on how to do this...
Any help would be much appreciated!

hibernate criteria. self join for denormalized table

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

Hibernate ManyToOne with #Formula

I have two database tables and would like to set up a many to one relationship between the two using Hibernate.
I did not construct these two tables, but were already made when I started on the project. I am new to Hibernate and would like to make a ManyToOne relationship between the two tables.
This normally would be strait forward, but the link between the two tables, "Praxiscode" is not the primary key, and I would like to do something like
#ManyToOne(targetEntity = PraxisIITest.class)
#Fetch(FetchMode.JOIN)
#NotFound(action = NotFoundAction.IGNORE)
#Formula(value = "(SELECT praxis.ID FROM lstPraxis praxis where praxis.Praxiscode=Praxiscode and Testdate BETWEEN praxis.BeginDate AND praxis.EndDate)")
private PraxisIITest praxisIITest;
but when specifying the #Formula described above it throws an exception complaining that a column is not in 'field list'
org.hibernate.exception.SQLGrammarException: Unknown column 'praxisiite1_.praxisIITest_ID' in 'field list'
org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:82)
Here is where ID is specified in PraxisIITest ->
#Entity
#Table(name="lstPraxis")
#Cache(region="edu.uky.cepis.cache.praxisIItest", usage=CacheConcurrencyStrategy.READ_WRITE)
public class PraxisIITest implements java.util.Comparator<PraxisIITest>, Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="ID")
private long id;
Am I going about this all wrong? or am I missing something very basic, My understanding is this should work...
Any thoughts or advice is greatly appreciated! Thanks again in advance!
I think the problem is that you aren't using a valid SQL fragment; it assumes that Hibernate will do some aliasing:
(SELECT praxis.ID FROM lstPraxis praxis where praxis.Praxiscode=Praxiscode and Testdate BETWEEN praxis.BeginDate AND praxis.EndDate)
Testdate doesn't exist in lstPraxis table (according to your images), it is in the tbl20Praxis table. Even if that table is what the PraxisIITest entity is mapped to, I think you need to explicitly do the table join in your #Formula fragment.
I didn't think that Hibernate did any processing of the formula, treating it as native SQL instead. But that makes the error you're seeing all the more confusing...

Hibernate mapping a specific field to be loaded by a table join

Is there a way I can map a field in an hibernate object to be loaded with a table query?
As an example lets say Table_Message has fields id(int),message_key(varchar),message_content(Clob),language(varchar). This table will hold messages in different languages(locale).
And another table thats mapped to an entity using hibernate. Comments with fields id(int),comment_message_id(varchar),created_date(datetime). comment_message_id refers to Table_Message's message_key column.
EDIT: Table_Message is NOT a mapped Entity in hibernate
Assuming my comment class is
public class Comment
{
int id;
String message;
Date createdDate;
}
Is there a way to tell hibernate to load message by joining Comment table and Table_Message table by message_key with a default locale (for example 'en').
Basically is there a way to tell hibernate to load a field by running a specific query? And if so what is that way?
I know about writing a Custom SQL query for loading the entity. But since I'm using XDoclet there doesn't seem to be a way to do that. Also it will be very convenient if there's a way to do that for a single field.
I guess ResultTransformer may help you in this. Please check
http://docs.jboss.org/hibernate/orm/3.3/api/org/hibernate/transform/ResultTransformer.html
http://stackoverflow.com/questions/6423948/resulttransformer-in-hibernate-return-null
You must join the tables by comment_message_id with message_key and further filter the result by language. I assume the message_key is unique.
As a side notice: you should use integer keys to have better performance.
You can try to write a database view in SQL and create an entity to opaque the view:
CREATE VIEW Comment_Table_Message AS
SELECT c.id, c.comment_message_id, c.created_date, m.id AS mid,
m.message_content, m.language
FROM Comment c, Table_Message m
WHERE c.comment_message_id = t.message_key;
Now you can create an entity CommentTableMessage and use JPQL to filter results by language:
SELECT x FROM CommentTableMessage x WHERE x.language=?1
If Table_Message was a Hibernate entity you would write (in JPA terms):
#Entity
public class Comment
{
int id;
#ManyToOne()
#JoinColumn(name="comment_message_id")
TableMessage tableMessage;
String message;
Date createdDate;
}
#Entity
public class TableMessage {
int id;
#Id
String messageKey;
bytes[] messageContent; //I don't know how you want to deal with Blobs?
String language;
}
Having that you can write a simple JPA Query: (Can you use JPA ? - next assumption)
SELECT c FROM Comment c WHERE c.tableMessage.language=?1

Categories