Greeting to all,
As I'm learning Java, JDBC and MySQL
I reach one point where I would like to perform the following
I have 2 entites
class User {
private Long id;
private String username;
...
...
private Set<Team> teams;
Constructors /
Getter/Setter
Second Entity
class Team {
private Long id;
private String name;
private Set<Users> users
Constructors/Getter/Setters
in my mysql there are 3 tables corresponding to User/Team and hybrid table where is the relationship between them users_teams holding user_id and team_id
My question is is there is a way when I call a sql query to select 1 team and all users in that particular team and get the info with ResultSet and build the Team object with the set of the users
or I need to do couple of sql queries to get the info separately and build the object later ?
Related
I've the following entity class and User table with same columns as below
public class User {
#EmbeddedId
#Column(name="USER_ID")
private String userId;
#Column(name="USER_EMAIL")
private String userEmail;
i am using the above entity class for both save and get user details from db and my get query is
SELECT * FROM ( SELECT * FROM regmgmt.user WHERE active_ind = 'A' ORDER BY last_edited_date DESC ) OFFSET 0 ROWS FETCH NEXT 4 ROWS ONLY , i dynamically update OFFSet value.Now as per new get requirements i've to get the user name which in user_details table and also total count of User table.
public class UserDetails {
#EmbeddedId
#Column(name="USER_ID")
private String userId;
#Column(name="USER_NAME")
private String userName;
}
unfortunately, i can't make any changes to user table and but i can make changes to entity User.class, until it doesn't effect the pagination ,save and delete functionalities.what i am trying to achieve is , inner join user and user detail tables with matching userids and also get total count of users using single query and map it to user.class
I am using MVC pattern
I have two tables : Employee and Address
say,
Employee is like
-------------------
Id | Name | DeptId
-------------------
101 | Jake | 501
102 | Donald | 502
and I have one Department table like
-----------------------------
DeptId | Name | Description
-----------------------------
501 | IT | software assistance
502 | HR | Human resources
Now since I am using MVC these tables are mapped to classes
like
#Table(name="Employee")
Class Employee{
#Id
#Column(name="Id")
private Long id;
#Column(name="Name")
private String name;
#Column(name="DeptId")
private Long deptId;
#ManyToOne
#JoinColumn(name="DeptId", referencedColumnName="id", insertable=false,updatable=false)
private Department dept;
//getters and setters go here
}
and the other class Department (mapped to Department table)
#Table(name="Department")
Class Department{
#Id
#Column(name="Id")
private Long id;
#Column(name="Name")
private String name;
#Column(name="Description")
private String description;
//getters and setters go here
}
notice that Employee class has reference to an object of Department class.
This #ManyToOne and #JoinColumn annotations helps us in automatically retrieving corresponding department object along with an employee object
Its easy with queries directly in code
but how can this be done if I am to use only procedures or functions in my code
I have tried different methods , but it doesn't seem to help
Sometimes I get error something like
Cannot return resultset from a stored procedure in oracle 10g
Can anyone please clarify. Also I have to use JNDI
Can I get my result from the procedure/function in a way that it returns me List<Employee> (not a raw resultset which I myself have to sort out into objects) . It should be possible using hibernate no ?
thanks
Your PLSQL needs to return a ref cursor.
JPA 2.1 has support for mapping CallableStatement out cursors to Entities. See this answer.
I am writing pseudocode ( Not the working example.) But it should solve your problem.
Oracle
CREATE OR REPLACE PROCEDURE getEmployees(deptName varchar(20))
BEGIN
SELECT * FROM Employee where DeptId in ( select DeptId from Department where Name =deptName );
END;
/
Hibernate
Query query = session.createSQLQuery(
"CALL GetStocks(:getEmployees)")
.addEntity(Employee.class)
.setParameter("deptName", "Production");
List result = query.list();
for(int i=0; i<result.size(); i++){
Employee emp = (Employee)result.get(i);
System.out.println(emp.toString());
}
I am trying to create a list of objects that contains different types of logs from my db. I would like to build the list such that the order is by most recently made (a date created field that's in each of the tables).
So is the only way to do it by getting each list (4 different kinds of logs) and then cycle through them and put them in the new list by comparing them and getting the most recent one each time? This seems like it could take a long time if the list are really long which they may or may not be.
IS there a better way to do it with Hibernate where I could put all the tables together and have it do the work for me? The tables don't share any keys or anything for a normal join?
Any suggestions would be helpful.
contactLog
has columns (Id, memberId, phonenumber, email, address, dateChanged)
salaryLog
has columns (Id, memberId, salary, dateChanged)
relationsLog
has columns (Id, memberId, relationId, dateChanged)
personalInfoLog
has columns (Id, memberId, height, weight, eyeColor, hairColor, dateChanged)
The purpose of these logs is to indicate anytime someone changes information and Im trying to provide the user with a audit page that will show all changes to these different objects.
I suggest using UNION, but if I'm not mistaken, HQL does not support UNION, so you'll have to use native query and result transformer. Here's a sample:
public class Log {
private Long id;
private Long memberId;
private String logType;
private Date dateChanged;
// getters & setters here
}
public class LogService {
#PersistenceContext
private EntityManager em;
public List<Log> getLogs(){
final Session sess = em.unwrap(Session.class);
final SQLQuery query = session.createSQLQuery(
"select id,memberId,'CONTACT' as logType, dateChanged from contactLog"+
"union select id,memberId,'SALARY' as logType,dateChanged from salaryLog"+
"union select id,memberId,'RELATIONS' as logType,dateChanged from relationsLog"+
"union select id,memberId,'PERSONAL INFO' as logType,dateChanged from personalInfoLog "+
"order by dateChanged desc";
);
query.setResultTransformer(Transformers.aliasToBean(Log.class));
return query.list();
}
}
Notice that only common columns are selected (because you must select the same number of columns from each table when using union).
If you want to view the full details of the log, just use the id to load the specific log and the log type to know from which table you would have to look for the full information.
or
You could modify the query to concat all the changed information into one column for all the tables (which means adding a new field in Log.class).
public class Log {
private Long id;
private Long memberId;
private String logType;
private Date dateChanged;
private String changedInfo;
// getters & setters here
}
"select id,memberId,'CONTACT' as logType, dateChanged, phonenumber||','||email||','||address as changedInfo from contactLog"+
"union select id,memberId,'SALARY' as logType,dateChanged,salary as changedInfo from salaryLog"+
"union select id,memberId,'RELATIONS' as logType,dateChanged,relationId as changedInfo from relationsLog"+
"union select id,memberId,'PERSONAL INFO' as logType,dateChanged, height||','|| weight||','|| eyeColor||','|| hairColor as changedInfo from personalInfoLog "+
"order by dateChanged desc
An another approch will be to create a view on your database, and use spring and hibernate as usual.
How can I join two tables by using java play framework and jpa, I really have a hardtime converting my MySQL query to jpa query.
Here is the MySQL query that I used in my old Java code:
SELECT * FROM tbl_majors
INNER JOIN tbl_lookup_user_major
ON tbl_majors.id=tbl_lookup_user_major.majorId
WHERE tbl_lookup_user_major.userId=12
//Table 1:
#Entity
#Table(name="tbl_majors")
public class Major extends Model {
public Major(){
}
#Column(name="major_name")
private String name;
#Column(name="major_desc")
private String description;
}
//Table 2
#Entity
#Table(name="tbl_lookup_user_major")
public class LookupUserMajor extends Model {
public LookupUserMajor(){
}
private int majorId;
private int userId;
}
Dont know if I get the exact point here, but in the tutorial blog "YABE", this kind of join table is used and created automatically by Play :
http://www.playframework.org/documentation/1.2.4/guide6#tagging
The many-to-many relation is described in the Model (between "Post" and "Tag" here for the blog sample) :
#ManyToMany(cascade=CascadeType.PERSIST)
public Set<Tag> tags;
public Post(User author, String title, String content) {
...
this.tags = new TreeSet<Tag>();
...
this.title = title;
this.content = content;
...
}
The YAML for the Posts data is :
Post(jeffPost):
title: The MVC application
postedAt: 2009-06-06
author: jeff
tags:
- play
- architecture
- mvc
After running the app, I check the database and the table "post_tag" is automatically created and all the links between the two tables are done (post_ids and tags_ids are filled).
Retrieving data seems as easy as :
"select distinct p from Post p join p.tags as t"
Can someone confirm that ? Because new to Java and JPA and Play ^^
If this is correct, it looks easier than managing the join table "manually".
Every time you have a field names "xxxId" in an entity, and "xxxId" is the ID of another entity, you did something wrong. The point of JPA is to manipulate objects, and associations between objects using object references or object collections.
Your tbl_lookup_user_major looks like a join table to me. Such a join table means that you have a many-to-many (or one-to-many, is one of the IDs is unique) between Major and User. So, your Major entity should have the following field :
#ManyToMany
#JoinTable(...) // details omitted
private Set<User> users;
And your JPA query should look like
select m from Major m
inner join m.users user
where user.id = :userId
Example Jpa query try like this...
Query query = JPA.em().createQuery(" SELECT * FROM "+User.class.getName() +" AS a JOIN "+
Role.class.getName()+" AS b WHERE a.roleId=b.roleId ");
I am playing around with JPA and other Java EE 6 stuff, but now I am facing some problems with a types query using the criteria Builder.
The business case for my poc is a twitter clone, so I have users which has a list of subscribers and subscriptions and I got Tweets.
#Entity
public class Tweet {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#ManyToOne
private TwitterUser author;
#ManyToOne
private TwitterUser receiver;
#Temporal(TemporalType.TIMESTAMP)
private Date datetime;
private String message;
}
#Entity
public class TwitterUser {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String username;
private String displayname;
private String password;
private String email;
#Temporal(TemporalType.TIMESTAMP)
private Date since;
#ManyToMany(cascade=CascadeType.ALL)
private List<TwitterUser> subscriptions;
#ManyToMany(mappedBy = "subscriptions")
private List<TwitterUser> subscribers;
}
The datamodel generated by JPA consists of 3 tables: Tweet, TwitterUser and TwitterUser_TwitterUser. Everything's fine so far. Basic queries do work well.
Now I want to select all Tweets for a timeline, what means all tweets of users, who are in the list of subscriptions of the current logged in user. I thought of a solution by using a subselect, so my sql would look like:
select * from TWEET where author_id in (
select subscriptions_ID from TWITTERUSER_TWITTERUSER where subscribers_ID = ?loggedInUserId);
This query works well, but I have no idea how to write it down using the CriteriaBuilder and generics. I don't even get a compilable piece of code that could fail at some other point, because I am not sure what the type of the subquery should be.
I was searching through lots of examples now, but they are mostly just using raw-types or using the subquery for retrieving the element of the lefthand-side of the in-clause.
Maybe I miss the wood for trees but I am really perplexed here. :(
In JPQL, one way of expressing this would be something akin to the following:
SELECT
tweet
FROM
Tweet tweet JOIN tweet.author author
WHERE
EXISTS (
SELECT
user
FROM
TwitterUser user JOIN user.subscriptions subscriber
WHERE
user = :loggedinUser AND
subscriber = author
)
As Criterias following the JPQL model almost directly, maybe this gets you started.
So thanks again to you guys helping me. I finally managed to find a solution with your input and it looks as follows:
public List<Tweet> findAllForSubscriber(TwitterUser user) {
// Select tweets
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tweet> cq = cb.createQuery(Tweet.class);
Root<Tweet> tweet = cq.from(Tweet.class);
cq.select(Tweet);
// Select subscribers of user
Subquery<Long> sq = cq.subquery(Long.class);
Root<TwitterUser> twitterUser = sq.from(TwitterUser.class);
Join<TwitterUser, TwitterUser> subscriptions = twitterUser.join(TwitterUser_.subscriptions);
sq.select(subscriptions.get(TwitterUser_.id));
sq.where(cb.equal(twitterUser, user));
// Where authorId in list of subscribers
cq.where(cb.in(tweet.get(Tweet_.author).get(TwitterUser_.id)).value(sq));
//
return em.createQuery(cq).getResultList();
}
My drawbacks were:
The Criteria API is just able to
do a compare of objects within an
equal() but not within a in()
statement. But I did not get a
helpful exception, all that was
generated was a wrong query (eclipselink & derby) :(
The in() statement
takes the lefthand-side of the in
statement, the value statement takes
the list of possibilities, the
wording confused me.
I cannot simply access the ids
of all subscriptions, I have to use a
join. It's quite clear if you think
about the table structure but I
missed that when simply thinking of
my objects.
P.S.: My solution totally misses to select the tweets of the user himself! ^^
There is a similar Criteria query example here,
http://en.wikibooks.org/wiki/Java_Persistence/Querying#Subselect.2C_querying_all_of_a_ManyToMany_relationship