I have 3 tables, Role[roleId, roleName], Token[tokenID, tokenName] & ROLETOKENASSOCIATION[roleId, tokenID]. The 3rd one was created automatically by hibernate. Now if i simply write a Query to get all the objects from Role class means, it gives the all role objects along with the associated tokenID & tokenName.
I just wanted the association as unidirectional. i.e: Roles--->Tokens
So the annotation in the Role class looks like,
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int roleId;
private String roleName;
#ManyToMany
#JoinTable(name="ROLE_TOKEN_ASSOCIATION",
joinColumns={#JoinColumn(name="roleId")},
inverseJoinColumns={#JoinColumn(name="tokenID")})
private List<Token> tkns;
//Getters & Setters
Now i want the tokenNames for the specific roleId.
First i made a query like this SELECT tkns.tokenName FROM Role WHERE Role.roleId=:roleId
But, i ended up with some dereference error.
Then i changed the query to SELECT tkns FROM Role r WHERE r.roleId=:roleId
Now i have got what i wanted. But it comes with roleId too.
How shall i get tokenName itself?
Actually my problem is solved, but i would like to know how to do it.
It ll be helpful to me, if anyone explains the Query Construction.
Any suggestions!!
Have you tried
SELECT t.tokenName FROM Role r JOIN r.tkns t WHERE r.roleId = :roleId
EDIT: This query almost directly maps to the corresponding SQL query where Role r JOIN r.tkns t is a shorthand syntax for the SQL join via the link table Role r JOIN ROLETOKENASSOCIATION rt ON r.roleId = rt.roleId JOIN Token ON rt.tokenId = t.tokenId. Affe's answer is another syntax for the same query.
See also:
Chapter 14. HQL: The Hibernate Query Language
You want a scalar list of just the name field? You should be able to get that like this
select t.name from Roles r, IN(r.tkns) t where r.roleId = :id
Related
I'm creating a JPA query where I want to sort on an email address. The table I'm querying is a Member table. This Member can EITHER point at an Account OR an Invite. Whether one of those associations is filled can be seen by the MemberStatus enumeration.
#Entity
public class Member {
#JoinColumn #ManyToOne private Account account;
#JoinColumn #OneToOne private Invite invite;
#Enumerated private MemberStatus status; //value can be INVITED or JOINED
}
So BOTH Account and Invite contain a String field called emailAddress. For the intents of this question, consider them to look like this:
#Entity
public class Account/Invite {
private String emailAddress;
}
I want to retrieve all members, left join on Account and Invite and sort on emailAddress. If I write a query like this:
#NamedQuery(
name="findMembers",
query="select m from Member m
left join m.invite i
left join m.account a
order by emailAddress asc"
)
Then I get an exception saying:
org.postgresql.util.PSQLException: ERROR: column "emailaddress" does
not exist Hint: Perhaps you meant to reference the column
"invite1_.email_address" or the column "account2_.email_address".
Which makes sense of course. But is there a way to add some alias to this emailAddress field depending on which left joined table is present? Is this even possible in SQL, let alone JPA? From a database perspective I'm not sure how it would work.
Btw, I do not want to go in the direction of database inheritance where both these referenced entities have the emailAddress field. That has too many downsides compared to the benefit.
You could use SQLs coalesce function which should be supported in JPA>=2.0.
e.g.
#NamedQuery(
name="findMembers",
query="select m from Member m
left join m.invite i
left join m.account a
order by coalesce(i.emailAddress, a.emailAddress) asc"
)
I have an entity class called User with the variable username with an ElementCollection map to represent "friendship" between two users, mapped by the userId, the start date and the id of the friend. The code for that relation is as follows:
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "friendship", joinColumns = #JoinColumn(name="userId"))
#MapKeyColumn(name = "friendId")
#Column(name = "startDate")
private Map<Integer, Date> friendShipMap;
I want to display the friends on a profile page for each user. I know I can just access the map via Java and get the ids (and find the usernames for the friends like that), but I'd like to use a custom #Query to get all the friends usernames for a given id. Somehow, the map is confusing me and I fail to find a proper statement for this.
Any help on this is greatly appreciated.
Edit: To clarify, I would like to use a custom #Query statement for the following SQL statement:
select u.username from users u join friendship m on u.userId = m.friendId where m.userId = 1;
So I thought it would be basically like this:
#Query("SELECT u.username FROM users u join u.friendShipMap m on u.userId = key(m) where m.userId = :userId")
List<User> getFriends(#Param("userId") int userId);
But I can't use m.userId, it says "cannot dereference scalar collection element: userId".
The corresponding table looks like this:
userId | startDate |friendId
You can use this #Query
#Query("select u.username from Users u inner join u.friendship f where f.friendId = :userId")
Make sure that you have an association between your entities Users and Friendship. Should be a #OneToMany relation I think.
And it should be in a List<String> instead of Map.
EDIT:1
If I understand it correctly, you will need another class friendship.
Maybe you need an embeddable class (friendship) described here.
http://www.thejavageek.com/2014/01/31/jpa-elementcollection-annotation/
Or you can create a new entity.
http://www.concretepage.com/hibernate/elementcollection_hibernate_annotation
And this is also a good example:
https://en.wikibooks.org/wiki/Java_Persistence/ElementCollection
I have strange problem. I want to create database like this:
One student can has a lot of subjects. Student has one evaluation for one subject. So I have
class student with ID, Name, Surname and A_I id, like:
#Id
#GeneratedValue
long id_student;
In subject class I have:
#Id
#GeneratedValue
long id_subject;
String name;
double graduate
I have third class, named StudentWithGraduate:
#Id
#GeneratedValue
long id;
double evaluation;
#OneToOne
Student student;
#OneToOne
Subject subject;
I think I could do it better, but I don't know how. But it isn't a main problem. This, what I write up is working, but I want to do some joins in query like:
Vector<Object[]> v = (Vector<Object[]>) em.createQuery(
"select p.name, o.graduate from Student s
left join StudentWithGraduate o on s.id_student=o.student
left join Subject p on p.id_subject=o.subject where
s.surname='"+name+"'").getResultList();
And it throw an error:
Exception Description: Object comparisons can only be used with OneToOneMappings. Other mapping comparisons must be done through query keys or direct attribute level comparisons.
How can I change this DB scheme or change that query?
Sorry for my english.
PS. When I was doing research I found #joinTables, but I don't know how to use it..
You need a short introduction in JPQL, but I will try to quickly explain some missing parts:
In a JPQL query you do not write which are the JOIN conditions (i.e the ON expresions), and instead you navigate through your Entity Graph, beginning with an entity (below I begin with the StudentWithGraduate entity):
SELECT p.name, o.graduate FROM StudentWithGraduate o
LEFT JOIN o.student s
LEFT JOIN o.subject p
WHERE s.surname=:name
The ":name" is called a named parameter, which helps you agains SQL injections. In order to set a value for it, you write the following:
Query query = em.createQuery(aboveQuery);
query.setParameter("name", parameterValue);
//....the rest of parameters + getResultList();
How do I get JPA & JPQL to pass a complete join query to the RDBMS? For example,
SELECT e
FROM Employee e
WHERE a.runkey = e.runkey
AND e.middle = 'M'
AND a.state = 'MA'
With the following Employee class
#Entity
public class Employee implements Serializable {
blah ... blah
#OneToOne
#JoinColumn(
name = "runkey",
referencedColumnName = "runkey",
insertable=false, updatable=false)
private Address address;
}
and the JPQL,
SELECT e
FROM Employee e
INNER JOIN FETCH e.address AS a
WHERE a.state = :state
AND e.middle = :middle
I am able to get Hibernate JPA to pull the data as expected.
However, eclipselink croaks that it cannot traverse associated field "address".
If so, how then should I design the Employee entity and how should I phrase the JPQL in order to get eclipselink to execute a table join with WHERE filters on both tables?
(Rant: Otherwise Eclipselink JPA is no better than JDO!!!)
~
Further edit: Does this post mean anything to my case ....
https://forums.oracle.com/forums/thread.jspa?threadID=1568659
The problem is that you are trying to alias a join fetch which is not allowed according to the JPQL specs. Hibernate allows this anyway.
You can still obtain the desired behavior with EclipseLink using query hints.
Take a look at the following posts:
jpa fetch join query
EclipseLink JPQL (Glassfish v3): join fetch syntax problem?
The following link can also be useful:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/QueryOptimization
I'm piggy-backing off of How to join tables in unidirectional many-to-one condition?.
If you have two classes:
class A {
#Id
public Long id;
}
class B {
#Id
public Long id;
#ManyToOne
#JoinColumn(name = "parent_id", referencedColumnName = "id")
public A parent;
}
B -> A is a many to one relationship. I understand that I could add a Collection of Bs to A however I do not want that association.
So my actual question is, Is there an HQL or Criteria way of creating the SQL query:
select * from A left join B on (b.parent_id = a.id)
This will retrieve all A records with a Cartesian product of each B record that references A and will include A records that have no B referencing them.
If you use:
from A a, B b where b.a = a
then it is an inner join and you do not receive the A records that do not have a B referencing them.
I have not found a good way of doing this without two queries so anything less than that would be great.
Thanks.
I've made an example with what you posted and I think this may work:
select a,b from B as b left outer join b.parent as a in HQL.
I have to find a "criteria" way of doing that though.
You may do so by specifying the fetch attribute.
(10) fetch (optional) Choose between outer-join fetching and fetching by sequential select.
You find it at: Chapter 6. Collection Mapping, scroll down to: 6.2. Mapping a Collection
EDIT
I read in your question's comment that you wanted a way to perform a raw SQL query? Here a reference that might possibly be of interest:
Chapter 13 - Native SQL Queries
and if you want a way to make it possible through HQL:
Chapter 11. HQL: The Hibernate Query Language
In chapter 11, you want to scroll down to 11.3. Associations and joins.
IQuery q = session.CreateQuery(#"from A as ClassA left join B as ClassB");
I guess however that ClassB needs to be a member of ClassA. Further reasdings shall help.
Another thing that might proove to be useful to you are named queries:
<query name="PeopleByName">
from Person p
where p.Name like :name
</query>
And calling this query from within code like so:
using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction()) {
session.GetNamedQuery("PeopleByName")
.SetParameter("name", "ayende")
.List();
tx.Commit();
}
Please take a look at the referenced link by Ayende who explains it more in depth.