JPA Query ElementCollection key - java

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

Related

Using JPA to retrieve particular many-valued association columns

There is a column that's so huge, it slows the entire query speed.
So i need to ommit the one, only give when actualy needed.
I've tried this solution:
#Query("SELECT new Account (a.name) From Account a Where a.id = :id)
The above code will retrive the id column data.When I try to use other getter,obviously the rest property are all null.
but when it comes with other entity relation for example:
//The account entity code
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
#NotFound(action = NotFoundAction.IGNORE)
private User user;
/**
The user side code is ommitted
**/
#Query("SELECT new Account (a.name,a.user) From Account a)
it will generarte these sql query:
inner join
user user3_
on account0_.user_id=user3_.id
However, when we using the normal jpa method like
#Query("SELECT a FROM Account a WHERE a.id = :id")
Account getById(UUID id)
we can easily get the user entity with the getter method:
Account acc = accountRepository.getById(id);
User user = acc.getUser();
Not the inner join sql query;
How can I retrieve the paritcular association entity columns with getter?
Can it be possible to achieve with jpa?
This post should help : How to lazy load an entity attribute using JPA
Prior I strongly recommend you to understand what lazy loading is in JPA and how it works. These one could help : What is lazy loading in Hibernate? and Difference between FetchType LAZY and EAGER in Java Persistence API?

JPA Query with 2 inner joins and a sort based on either one of the joined objects

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"
)

JPA join tables through query

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();

JPQL table join query

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

How to write a HQL query for Many To Many Associations?

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

Categories

Resources