I want a single HQL query that returns all groups containing a given user that where created before a given date. Somehow I can't get it right.
public class Group
{
#ManyToMany
Set<User> users;
Date created;
}
public class User
{
...
}
II-Bhima's answer is essentially right - here is a little fix:
select g from Group as g
inner join g.users as user
where g.created < :createdDate
and user = :user
you need it so that Groups are returned and not Object[] with Group-User 2-tuples.
Related
I have the following relevant JPA annotated classes in a Spring-Boot JPA enabled project (All Groovy Code):
#Entity
abstract class Character {
#Id
String id;
String name;
#ElementCollection(targetClass = Episode)
#Enumerated(EnumType.ORDINAL)
Collection<Episode> appearsIn;
}
#Entity(name = "Human")
public class Human extends Character {
String homePlanet;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "favorite_droid_id")
Droid favoriteDroid;
}
public enum Episode {
PHANTOM_MENACE,
ATTACK_OF_THE_CLONES,
REVENGE_OF_THE_SITH,
A_NEW_HOPE,
EMPIRE_STRIKES_BACK,
RETURN_OF_THE_JEDI,
THE_FORCE_AWAKENS
}
When I attempt to execute the following JPA Query:
def query = em.createQuery("from Human h where h.appearsIn in (:episodes)");
query.setParameter("episodes", EnumSet.of(Episode.THE_FORCE_AWAKENS));
def result = query.getResultList();
The generated SQL statement does not seem to have the alias to the Character table or the column name for appears_in:
select human0_.id as id2_0_, human0_.name as name3_0_, human0_.favorite_droid_id as favorite6_0_, human0_.home_planet as home_pla5_0_
from character human0_
cross join character_appears_in appearsin1_
where human0_.dtype='Human' and human0_.id=appearsin1_.character_id and (. in (?))
I have also tried using equals instead of in, with the same behavior:
from Human h where h.appearsIn = :episode
Produces the following SQL:
select human0_.id as id2_0_, human0_.name as name3_0_, human0_.favorite_droid_id as favorite6_0_, human0_.home_planet as home_pla5_0_
from character human0_
cross join character_appears_in appearsin1_
where human0_.dtype='Human' and human0_.id=appearsin1_.character_id and .=?
Any help is greatly appreciated.
Your query is invalid - as #Neil Stockton pointed out, by writing h.appearsIn in (:episodes) you are saying "collection in collection" which does not make sense.
You should rather declare a "collection member variable" like this:
select distinct h
from Human h
join h.appearsIn ai
where ai in (:episodes)
ai represents a single element of appearsIn (like an iterator).
I am trying to find the maximum value of a Date column in mySQL DB using hibernate query language with join
#Query("select o.techid, CAST(MAX(o.last_modified) AS DATE)
from com.dw.model.user.User as u
left join com.dw.model.order.Order as o
on u.username=o.techid group by o.techid")
List<User> findUsers();
Model class =
#Entity(name = "orders")
#Scope("prototype")
#Component
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
public class Order {
#Id
private long orderNumber;
private Date last_modified;
I am getting this error :-
Caused by: java.lang.IllegalStateException: DOT node with no left-hand-side!
Can anyone please help me out by telling me how to write this in Hibernate?
Remove your package names. An entity is defined by its name only. Dots are used for properties and links between tables (when defined as a #ManyToOne* property).
select o.techid, CAST(MAX(o.last_modified) AS DATE)
from User as u
left join Order as o
on u.username=o.techid group by o.techid
Think Classes and Properties, not columns, when you write HQL.
Try following solution, this should work
SELECT o.techid, CAST(MAX(o.last_modified) AS DATE)
FROM User u LEFT JOIN u.order o GROUP BY o.techid
Say I want to get all rows of the MyEntity that have an id lower than 10. This entity contains a list of Another entity. I would like this list to be fetched only by a subset of the listAnother. This subset containing only Another where the user contained in it is a specific one.
Basically in SQL it would be like this :
SELECT * FROM myentity m
LEFT JOIN another a
ON m.idTable=a.my_entity
AND a.user = "test1"
WHERE m.idTable < 10;
I didn't manage however to translate this query to jpql.
My entities being like this :
#Entity
public class MyEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idTable;
#OneToMany(mappedBy = "myEntity")
private List<Another> listAnother;
}
#Entity
public class Another implements Serializable {
#Id
private int idAnother;
// bi-directional many-to-one association to Thethread
#ManyToOne(fetch = FetchType.LAZY)
private MyEntity myEntity;
#ManyToOne(fetch = FetchType.LAZY)
private User user;
}
#Entity
public class User implements Serializable {
#Id
private String username;
}
In jpa I could do this :
SELECT m FROM MyEntity where m.idTable < 10;
And then for each entity I get from this list call this:
SELECT a FROM Another Where a.user.username=:'test' AND a.myEntity=:entity;
However I would like to do it all at once in one query. Can I do this with criteria ? I didn't take the time to learn it but if it's possible then I will.
JPQL and Critaria API are equal in terms of what you can express with them. What is possible with JPQL is possible with Criteria and vice versa.
With JPQL, you can simply combine your 2 queries into one in this way:
SELECT a FROM Another a Where a.user.username=:test AND a.myEntity.idTable < 10
You can use dot notation (.) to join multiple entities in the query, provided that the relationship is X-to-one. If you have X-to-many relationship, you need to use JPQL JOIN, which is not very complicated. Example with (LEFT) JOIN:
SELECT m FROM MyEntity m LEFT JOIN m.listAnother a Where a.user.username=:test AND m.idTable < 10
The result is of course not equal - in first case you will get list of Another entities and you can get MyEntity by a.myEntity, in the second case you will get list of MyEntity, which all have at least one Another entity with given user
In hibernate you can use Filters and FilterJoinTable. Here you can read how to do that. Similar problem was solved here.
You need to extend the logic which you applied to check the username (a.user.username=:'test') which was for many-to-one relation between anything and user by taking it one level up to myEntity and then using it for one-to-many relation as well -
SELECT m FROM MyEntity where m.idTable < 10 and (m.listAnother.user.username=:'test')
The join condition "m.listAnother.myEntity=:entity" wouldn't be needed now as in our query we have started from the specific myEntity and then moved down to listAnother.user.username .
I don't have the table definitions to try this query myself, exact SQL may require some tweaks - but logically it should work like the way I showed above, i.e. just the way you joined Another with User, the same way you can join MyEntity with Another by just traversing down the child listAnother.
I have three entities with relation UserDetails hasmany FiledTask and Task hasMany FiledTask. All I want is list of FiledTask of particular User
For UserDetails:
#OneToMany(mappedBy="user",cascade=CascadeType.ALL)
Collection<FiledTask> filedTasks = new ArrayList<FiledTask>();
And for Tasks I have
#OneToMany(mappedBy="task")
Collection<FiledTask> filedTasks = new ArrayList<FiledTask>();
And FiledTask looks like
#ManyToOne
#JoinColumn(nullable = false, name = "taskId")
private Tasks task;
#ManyToOne
#JoinColumn(nullable = false, name = "userId")
private UserDetails user;
I have tried
query = session.createQuery("from Tasks as tasks inner join tasks.filedTasks as files with files.user = :user");
query.setParameter("user", user); //user is UserDetails instance
But I am getting error clause can only reference columns in the driving table, means FiledTask can't userId for comparision?
with clause can only reference columns in the driving table [from com.akhi.app.cdm.Tasks as tasks inner join tasks.filedTasks as files with files.user = :user]
If you want the FiledTasks of a given user, then the easiest thing to do is
UserDetails user = session.find(UserDetails.class, userId);
Collection<FiledTask> filesTasks = user.getFiledTasks();
Using HQL, it would be
select f from FiledTask f where f.user = :user
If what you want is in fact the tasks of a given user, then the query would simply be
select t from Tasks t
inner join t.filedTasks filedTask
where filedTask.user = :user
Note that the entity Tasks shouldbe named Task. An instance represents a single task, and not multiple ones.
OK, looks like there is a bug in Hibernate
https://hibernate.atlassian.net/browse/HHH-2772
I think in your case what you need to do is
query = session.createQuery("from Tasks as tasks inner join tasks.filedTasks as files with files.user.id = :userId");
query.setParameter("userId", user.id);
Hope this helps somebody. I spend several hours on this.
I had the same problem using a MySql (Inno) DB plus my dialect class derived from Hibernate's MySQL5InnoDBDialect - class.
I had to override the supportsRowValueConstructorSyntax-method and let it return false as MySQLDialect (which is the base class of MySQL5InnoDBDialect) returns true.
#Override
public boolean supportsRowValueConstructorSyntax() {
return false;
}
Doing this, hibernate does not use the object reference (in your case .user) in order to create a tuple for the comparison. I hope, this will help.
Using JPA, I want to select all Log objects for a specific actiontype. From the log object I want to get the user (log.getUser()), but the users appear several times in the result list. I tried it with distinct, but it did not work, I guess because I was not able to define, what exactly has to be distinct. Here is my JPA query:
SELECT DISTINCT log
FROM Log AS log JOIN log.action AS action
JOIN log.user AS user
WHERE action.actionType = :actionType
If I say SELECT DISTINCT user, then I don't have the whole log object in the end.
Any help or hint would be appreciated.
Edit:
Part of my Log Class:
public class Log {
private int logId;
private Calendar logDate;
private User user;
private Action action;
private String description;
....
}
Two Queries Solution
Since you want Log objects and distinct User objects you could do two queries, first one to retrieve the Log objects and second one to retrieve distict User objects.
// first one to select Log objects
String logQuery = "SELECT l FROM Log l WHERE l.actionType = :actionType";
...
List<Log> logs = logJpaQuery.getResultList();
// second one to select distinct users from this objects
String usersQuery = "SELECT distinct l.user FROM Log l where l.logId in (:logIds)";
...
userJpaQuery.setParameter("logIds", logs);
List<User> users = userJpaQuery.getResultList();
With this approach you have the distinct users for the select Logs objects.