Batch load a lazily loaded Hibernate property - java

Suppose I have a:
class Student {
int id;
String name;
List<Course> courses; //Lazily loaded as per Hiberante config
}
Now suppose I have a List students and in order to optimize fetching List for all these students, I was to batch select them rather than letting Hibernate call a separate SQL one by one. I cannot turn off lazy loading as in many other code paths I will not access course property.
I can certainly write a function that will take in a list of courseIds and return a List and then attach these objects to the Hibernate session but these objects won't be associated with the Student objects loaded by Hibernate. If I call something like student.setCourses(), then I run into the risk that Hibernate will consider the session to be dirty and try updating the Student objects.
I would really like to hear from people who have faced similar issues when using Hibernate.

Write a specific hibernate query to get the student class with a 'join fetch' to get all related courses in a single query. Example:
from Student s left join fetch s.courses

Related

Spring JPA Hibernate DeleteByColumnName behaves very inefficient

I was trying to use the Spring's CrudRepository work with Hibernate to delete rows by a non-primary-key column, using deleteByColumnName method. However, the actual executed query is very inefficient and too slow in practice.
Suppose I have two tables Project and Employee, and each employee is in charge of some projects, which implies that the Project table has a field employee_id. Now I would like to delete some projects by employee_id. I wrote something like
public interface ProjectRepository extends CrudRepository<Project, String> {
#Transactional
void deleteByEmployeeId(String employeeId);
}
What I am expecting is Hibernate will execute the following query for this method
DELETE FROM Project
WHERE employee_id = ?
However, Hibernate executes it in a drastically slow way like
SELECT id FROM Project
WHERE employee_id = ?
Hibernate stores the above result in a list, and execute
DELETE FROM Project
WHERE id = ?
for N times... (it executes in batch though)
To address this inefficiency problem, I have to override the method by writing SQL directly, like
public interface ProjectRepository extends CrudRepository<Project, String> {
#Query("DELETE FROM Project p where p.employee_id = ?1")
#Modifying
#Transactional
void deleteByEmployeeId(String employeeId);
}
Then the behavior will be exactly the same as what I am expecting.
The performance is substantially distinct when I delete about 1k rows in a table containing around 500k entries. The first method will take 45 seconds to finish the deleting compared to the second methods taking only 250ms!
The reason I use Hibernate is taking advantage of its ORM strategy that avoids the use of SQL language directly, which is easy to maintain in the long run. At this point, is there anyone who know how to let Hibernate execute the deletion in the manner of my second method without directly writing the SQL? Is there something I am missing to optimize the Hibernate performance?
Thanks in advance!
Here you can find a good explanation why Hibernate has this bad performace when deleting Project items Best Practices for Many-To-One and One-To-Many Association Mappings

Sorting CREATE TABLE statements, which contains references in Java

my project is about to create my own persistence implementation. Maybe it's easy but I can't find the solution. I have Classes annotated with my own annotation #Entity and in Annotation Processor I want to create SQL create table statements and save them into file and then execute them. But how do I sort these statements? I have references in tables, I have to first create the non referencing table and then table referencing on this first table
Ok. I will be concrete. Imagine you have for example 3 Classes: Person Department and Company. They are annotated as Entities and I want to create the SQL statements for create tables. But Company references on Department and Person references on Department, so I have to first create the Department table and then Person or Company. I am creating the statements in Annotation Processor, so I have for disposal the annotated elements. Now I am just sorting String to be written in file. But it isn't very pretty.
ArrayList<String> sortedListOfCommands = new ArrayList<>();
for(String command: listOfCommands){
if(!command.contains("FOREIGN"))
sortedListOfCommands.add(command);
}
for(String command: listOfCommands){
if(!sortedListOfCommands.contains(command))
sortedListOfCommands.add(command);
}

Object Relational mapping and performance

I am currently working on a product that works with Hibernate (HQL) and another one that works with JPQL. As much as I like the concept of the mapping from a relational structure (database) to an object (Java class), I am not convinced of the performance.
EXAMPLE:
Java:
public class Person{
private String name;
private int age;
private char sex;
private List<Person> children;
//...
}
I want to get attribute age of a certain Person. A person with 10 children (he has been very busy). With Hibernate or JPQL you would retrieve the person as an object.
HQL:
SELECT p
FROM my.package.Person as p
WHERE p.name = 'Hazaart'
Not only will I be retrieving the other attributes of the person that I don't need, it will also retrieve all the children of that person and their attributes. And they might have children as well and so on... This would mean more tables would be accessed on database level than needed.
Conclusion:
I understand the advantages of Object Relational Mapping. However it would seem that in a lot of cases you will not need every attribute of a certain object. Especially in a complex system. It would seem like the advantages do not nearly justify the performance loss. I've always learned performance should be the main concern.
Can anyone please share their opinion? Maybe I am looking at it the wrong way, maybe I am using it the wrong way...
I'm not familiar with JPQL, but if you set up Hiernate correctly, it will not automatically fetch the children. Instead it will return a proxy list, which will fetch the missing data transparently if it is accessed.
This will also work with simple references to other persistent objects. Hibernate will create a proxy object, containing only the ID, and load the actual data only if it is accessed. ("lazy loading")
This of couse has some limitations (like persistent class hierarchies), but overall works pretty good.
BTW, you should use List<Person> to reference the children. I'm not sure that Hibernate can use a proxy List if you specify a specific implementation.
Update:
In the example above, Hibernate will load the attributes name, age and sex, and will create a List<Person> proxy object that initially contains no data.
Once the application accesses calls any method of the List that requires knowledge of the data, like childen.size() or iterates over the list, the proxy will call Hibernate to read the children objects and populate the List. The cildren objects, being instances of Person, will also contain a proxy List<Person> of their children.
There are some optimizations hibernate might perform in the background, like loading the children for other Person objects at the same time that might be in this session, since it is querying the database anyways. But whether this is done, and to what extend, is configurable per attribute.
You can also tell hibernate to never use lazy-loading for certain references or classes, if you are sure you'll need them later, or if you continue to use the persistent oject once the session is closed.
Be aware that lazy loading will of course fail if the session is no longer active. If for example you load a Person oject, don't access the children List, and close the session, a call to children.size() for example will fail.
IIRC the hibernate session class has method to populate all not-yet-loaded references in a persistent oject, if needed.
Best read the hibernate documentation on how to configure all this.

access data from table in many to many relationship in hibernate

I have three table's student , course , student_course
table student
{
student_id(PK)
}
table course
{
course_id(PK)
}
table student_course
{
student_id(PK+FK)
course_id(PK+FK)
}
I created model class's and configuration files using Hibernate Generation Tool.
It create following files-
1) student.java & student.hbm.xml
2) course.java & course.hbm.xml
And for student_course it creates set in each hbm file with Many-to-Many relationship.
So I want Course object's related to student, for this i want to access student_course table separately.
Right Now i access Course object related to student by accessing set of student_course through student object.I think it is not efficient one.
What is the efficient way to this?
Can i do this
by writing sql query or
by manually creating studentCourse.java & studentCourse.hbm.xml
please suggest me efficient way to access course object's related to student object.
please suggest me efficient way to access course object's related to
student object.
I think what you've got it the right approach. There is a link table but Hibernate has hidden it through the use of a ManyToMany - this is the correct modelling for this relationship. A student can take many courses and a course has many students.

How to select property from an entity in a hibernate relation

I have an entity class set up in Java, with a many-to-many relationship to another class. However, rather than selecting the entire entity collection, I'd like to select only a property from the child entities. The reason for doing this is that it will lower the amount of data being loaded into the system as I don't always need the entire entity depending on my view.
This is what I have so far:
#Entity
public class Disposition {
...
#ManyToMany
private List<Project> projects;
...
}
This works fine and retrieves a list of Project instances. However, I don't want to get all the Projects for the Disposition; I only want to retrieve Project.name.
The only solution I've been able to come up with so far is using the #Formula annotation but I'd like to avoid this if possible since it requires writing native SQL instead of HQL.
This view is read-only so I don't expect any changes to the data to be persisted.
you can use hql to only get the child's name. It would look something like
"select p.name from Project p where p.parent_id = ?"
you would have to tailor the variable names in that, and use a parameterized query to replace the ? with the id of the parent.
It is common to have tailored DAO methods for exactly this sort of situation.
This is where object relational mapping cannot help you anymore. But you can use the Query API which allows to query arbitrary objects by HQL, not SQL. Isn't #Formula using HQL, too?
It is not Hibernate, but the ebean project could interrest you. Ebean is an ORM project using the JPA annotations and allowing the lazy (partial) loading of objects.
In your example, getting only project names would result in this code:
List<Project> projects = Ebean.find(Project.class)
.select("name") // Only name properties are loaded
.where().eq("disposition", yourDisposition)
.findList();
Then, if you try to get project owner (or every other property), theses properties will be lazy loaded by Ebean.
Check out org.hibernate.criterion.Projections. Given a Criteria you can simply do the following:
criteria.setProjection(Projections.property("name"));

Categories