Hibernate inheritance query - java

I have 4 entities:
User, Teacher, Student, Course
and 4 tables:
t_user, t_teacher_course, t_student_course, t_course
Teacher and Student extends User (with descriminators) and have #ManyToMany relationship with Course (User do NOT have)
Teacher's relations stored in t_teacher_course and Student's relations stored in t_student_course.
Now i want to select all users with courses (if they exists) in one query
select u from User u left join fetch u.courses c (notice that User do not have courses)
This select generated something like this:
select
...
from
T_USER user0_
left outer join
T_TEACHER_COURSE course1_
on user0_.USERID_=courses1_.TEACHER_
left outer join
T_COURSE course2_
on courses1_.LANE_=course2_.COURSENAME_
where
user0_.GROUP_=?
As you can see clearly Hibernate did NOT join with t_student_course table
I am using Hibernate 4.1Final
Question:
Does Hibernate support such queries
a) if supports then why it didn't fetched courses for Student entity?
b) if do not support than how can i select all users with their courses using JPQL?

Since u.courses could be student.courses or teacher.courses, Hibernate resolves the ambiguity by choosing the first (or last) association with this name in its metadata.
It might work if the name of the courses collection is not the same in both subclasses. For example, you could define Student.attendedCourses and Teacher.teachedCourses.
Otherwise, you'll have to issue two queries (one for teachers and one for students), and join the result lists. Or you'll have to pull up the association in the User entity.

Related

How can I improve the performance when using TABLE_PER_CLASS that causes several lot of tables in a queries?

I have a tree structure defined in hibernate. Where I have an abstract element called TreeObject. A tree object can have several children and only one parent.
I also have some implementation for this class: form, category, group of questions and question. All of them inherits from TreeObject.
The idea is that a form can have as children categories and questions. The category can have as children groups and questions, and groups can have as children other groups and questions.
Then I have defined the TreeObject as:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class TreeObject{
#ManyToOne
private TreeObject parent;
#OneToMany(mappedBy = "parent")
private List<TreeObject> children;
[...]
}
Then, the other objects are very simple. For example, the form element is:
#Entity
public class Form extends TreeObject {
[...]
}
And the other elements are similar, except by some irrelevant code for this question.
The problem resides when I want to retrieve the children of an element (as TreeObject is not a real table in the database). For example, to get all children of a form, hibernates create multiples union from the tables Form, Category, Group, Question for representing the TreeObject table equivalence and selecting the children. When the database has several elements (but not so much), getting the children can takes around 0.5secs due to the multiple union generated. Then when I will have a big amount of data, I am going to have big performance issues with that query.
For example, an example of a query obtained to get a form is:
select form0_.ID as ID1_7_0_, form0_.createdBy as createdB3_7_0_, form0_.name as name2_12_0_, form0_.parent_ID as parent_I5_12_0_, children1_.parent_ID as parent_I5_7_1_, children1_.ID as ID1_12_1_, children1_.ID as ID1_7_2_, children1_.createdBy as createdB3_7_2_, children1_.name as name2_12_2_, children1_.parent_ID as parent_I5_12_2_, children1_.version as version2_2_2_, children1_.clazz_ as clazz_2_, questionva2_.BaseQuestionWithValue_ID as BaseQues1_7_3_, questionva2_.questionValues as question2_38_3_, treeobject3_.ID as ID1_7_4_, treeobject3_.comparationId as comparat2_7_4_, treeobject3_.name as name2_12_4_, treeobject3_.parent_ID as parent_I5_12_4_, treeobject3_.clazz_ as clazz_4_ from form form0_ left outer join
( select ID, name, parent_ID, 10 as clazz_ from questions
union select ID, name, parent_ID, 24 as clazz_ from group
union select ID, name, parent_ID, 32 as clazz_ from category
union select ID, name, parent_ID, 26 as clazz_ from form )
children1_ on form0_.ID=children1_.parent_ID left outer join
question_with_values questionva2_ on children1_.ID=questionva2_.BaseQuestionWithValue_ID left outer join
( select ID, name, parent_ID, 10 as clazz_ from questions
union select ID, name, parent_ID, 24 as clazz_ from group
union select ID, name, originalReference, parent_ID, 32 as clazz_ fromcategory
union select ID, comparationId, name, parent_ID, 26 as clazz_ from form )
treeobject3_ on form0_.parent_ID=treeobject3_.ID where form0_.ID=344820 order by children1_.sortSeq asc;
(note: I have removed several columns to make it simpler to understand the code)
Now I have use #BatchSize to increase performance, and the general performance of the application is better, but still is not a real solution.
My idea is to use something like #WhereJoinTable to filter the 'big' union query and only retrieve the real children from Category and Questions and not all of them, avoiding the performance issue. But as children parameter is mappedBy by parent, I have not any clue how can I achieve this.
#ManyToOne
#JoinColumn(name="parent_ID")
#WhereJoinTable(clause=" ???? ")
private TreeObject parent;
Maybe with #Filter option of Hibernate:
#ManyToOne
#JoinColumn(name="parent_ID")
#Filter(name="parentGroup",condition=" ???? ")
private TreeObject parent;
Of course, another solution is to change the InheritanceType.TABLE_PER_CLASS to only have one big table and therefore the union will not appear in the query. But the database will be very hard to read, and I want to avoid it.
The question is: exists any way to improve the Hibernate performance for retrieve all children of a TreeObject?
A ManyToOne annotation is by default EAGER and I think you don't really need the parent of the objects you are loading directly (via primary key), right?
You could change the association like this:
#ManyToOne(fetch = FetchType.LAZY)
private TreeObject parent;
This should at least remove the last join with the unions.
But due to the nature of your model (it's a recursion) you will never be able to select an entire object graph without a native query, because JPA simply doesn't support it. Even a native query may not be the best solution and I think you should consider using a document store which enables you to store/load entire graphs in one operation.

How to fetch many-to-many relationship entity

I have following table structure
TABLE1
T1_ID
T1_Col1
TABLE2
T1_ID
T3_ID
TABLE3
T3_ID
T3_COL1
Table1 and Table3 are joined by a middle table which is Table2. Now I have only T1_ID and I want to fetch all the rows from Table3 which are associated with T1_ID. A simple SQL query would be
select T1.*, T3.*
from TABLE1 T1, TABLE T2, TABLE3 T3
where T1.T1_ID = T2.T1_ID
and T2.T3_ID = T3.T3_ID
So how can i do this in hibernate/jpa ... I have yet to write my entity classes for Table1, Table2, Table3. I want to execute this query as part of Table1, so that i can write a method say entity.fetchAssociatedTable3(). The easiest approach i can think of is in fetchAssociatedTable3 i can put custom queries like the one i mentioned above. But since i am using hibernate/jpa I want to know if there is a better way to do this.
UPDATE
Apparently, my question isn't clear enough. I want to do something as user Dragan Bozanovic mentioned. However, What i want to know that
How would i write Table1 entity ? I mean what annotations i would put on the columns etc which will make hibernate/jpa understand that this column is related to Table3 column via Table2
I guess if question 1 is answered, then it would be difficult to write getEntity3s() method. But if (for a noob) there is something that I need to know, I would appreciate.
Assuming that you will have a many-to-many association between Entity1 (mapped to TABLE1) and Entity3 (mapped to TABLE3), you can either:
1) read the Entity1 by id and get all of the Entity3s from it:
Entity1 entity1 = entityManager.find(Entity1.class, entity1Id);
Collection<Entity3> entity3s = entity1.getEntity3s();
2) or, execute the JPQL query to get Entity3s without loading the Entity1 instance:
select distinct e3 from Entity3 e3 join Entity1 e1 where e1.id = :entity1Id
First thing you would need do is to stop thinking in terms of tables when using ORM tool (Hibernate/JPA). You model your classes and their relations and let the ORM tool help with the mappings declaratively. Your join table just is serving here for creating relation many to many relation between two entities. So in terms of classes you would have only Entity1 and Entity3. You would not be creating a class representing join table (unless of course you want it to have other attributes other than foreign keys in which case it would qualify to be a Entity class in it's own right). And then you can use either method suggested by #Dragan i.e., loading by primary key or using explicit HQL/JPQL.

SELECT query for multiple column with multiple table

I attach one image of my problem:
In Testing jFrame jTextField I will insert customer id then after pressing ok button query will select and collect information related to that customer.Then it will show in the jTableModel.
I attach my database image.
Error is "SQL code cannot be executed".
You can do like this (without Join):
SELECT papers.paper_list,papers_rate.monday,papers_rate.tuesday,
papers_rate.wednesday,papers_rate.thrsday,papers_rate.friday,
papers_rate.saturday,papers_rate.sunday,magzines.magzine_name,magzines_rate.rate
FROM papers,papers_rate,magzines,magzines_rate
WHERE example_table.customer_id = ? AND other conditions"
This syntax is, in effect, a simple INNER JOIN. Some databases treat it exactly the same as an explicit JOIN. The WHERE clause tells the database which fields to correlate, and it returns results as if the tables listed were combined into a single table based on the provided conditions.(http://www.techrepublic.com/article/sql-basics-query-multiple-tables/)
You need to join the tables properly.
Like this:
SELECT
paper_list,monday,tuesday,wednesday,thrsday,friday,saturday,sunday,magzine_name,rate
FROM papers
LEFT JOIN papers_rate
ON papers_rate.paperId = papers.id
LEFT JOIN magzines
ON magzines.paperId = papers.id
LEFT JOIN magzines_rate
ON magzines_rate.magazineId = magzines.id
WHERE customer_id = ?"
If you do an inner join, all your results will vanish if you don't have a magazine_rate for example...
And check your spelling.
You're writing thrsday instead of thursday and magzine instead of magazine...
PS: And where does customer_id come from ?
Use joins to select multiple column from multiple tables. Refer this to get an understanding about the join and for join examples.
Note: There should be a common field between two tables to perform join operation
If the tables are related you must use JOIN: let's see an example (I don't know your tables fields, so I'll invent a custom example). Think about person and pet tables; the person tables could contain these fields:
Person (personID, first_name, last_name, age)
the pet table could contain these other fields:
Pet (petID, name, age, personID)
The personID field in the pet table identifies the owner of the pet. It is a simple 1:N relation. To select some values from these two tables you must do something like:
SELECT Person.first_name, Person.last_name, Pet.name
FROM Person INNER JOIN Pet ON
Person.personID = Pet.personID
WHERE Person.age > 30
This is just an example, clearly. And the INNER JOIN is just a join type (there are several join methods). Here you can find some documentation concerning these issues.
You need to either use a Join clause (... FROM papers JOIN papers_rate ON papers.[id_column] = papers_rate.[foreign_key]) or use an equi-join (replace JOIN...ON clause with a condition in the WHERE clause) (... FROM papers,papers_rate WHERE papers.[id] == papers_rate.[foreign_key])
Could you please post the schema of your tables?

Inner Join with NamedQuery?

I need to get data from three different tables and into a list. I was wondering how I do it with namedQuery? I've seen that it's possible by searching online but I just can't get it to work.
SELECT
Customer.name,
Customer.adress,
Orders.date,
Orders.order_id,
Product.product_name,
Product.price
FROM
Orders
INNER JOIN Customer ON Customer.customer_id=Orders.customer_id
INNER JOIN Product ON Product.product_id=Orders.product_id
ORDER BY
Orders.date
That's what I would want to convert to a namedQuery. It would be great if anyone could kick me in the right direction.
Seems I'm unfamiliar with the term named query.
But this is how you would do it in SQL
CREATE VIEW view_name AS
SELECT
Customer.name,
Customer.adress,
Orders.date,
Orders.order_id,
Product.product_name,
Product.price
FROM
Orders
INNER JOIN Customer ON Customer.customer_id=Orders.customer_id
INNER JOIN Product ON Product.product_id=Orders.product_id
ORDER BY
Orders.date
Then you can call it like so
SELECT * FROM view_name
Be warned though, views in views are terrible for performance.

Hibernate select with distinct - how does it work with an inner join?

First, I'm a total Hibernate novice.
Within hibernate, if you have an object, say author and author has a collection of books (say the list name is 'books'). If you run a Hibernate query, using using the following query I made up (not yet tested)
select distinct author from Author author inner join author.books as book
What exactly will the distinct do here?
The reason I ask is because I haven't selected a particular property in the select clause, such as
select distinct author.name ...
Also, what exactly will be unique about the objects which are returned?
First of all, if authors co-write books, you have a many-to-many association, and not a one-to-many.
That said, the query will return the list of all the authors who have written at least one book (that's the effect of the inner join). And each author will be exactly once in the returned list.

Categories

Resources