Eclipselink Shared Cache - Lazy associations - eclipselink

I'm devoloping an application using JPA eclipselink 2.6.4.
I'm enabling the shared cache for serveral JPA entities.
#Entity
#Cache(
type=CacheType.SOFT,
size=500
)
public class Tutor
{
#Id
#Column(name = "id")
private String id;
#Column(name = "name")
private String name;
... getters and setters
}
#Entity
#Cache(
type=CacheType.SOFT,
size=500
)
public class Student
{
#Id
#Column(name = "id")
private String id;
#Column(name = "name")
private String name;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="TUTOR_ID")
private Tutor tutor;
... getters and setters
}
I got a typical entity association of tutor and students. It is defined as LAZY because we want to avoid the "N + 1 problem" when a students query is done.
When we execute a students query and we want the association to be resolved, we use JOIN FETCH technique:
SELECT s FROM Student s JOIN FETCH s.tutor t WHERE s.id = :id
Up here all right.
The first time we execute the JPA query, because shared cache has no students yet, a database query is executed. We get the student entity populated with the tutor entity.
Nevertheless, the second time we execute the same query, there is a hit in the shared cache, so a database query is NOT executed. But then the student entity IS NOT populated with the tutor entity.
We would like to get the student entity populated with the tutor entity.
We have seen that this is possible changing the association to EAGER, but we don't want to change to EAGER to avoid "N + 1 problem".
Any idea?
Thanks

Related

Course has many students and many students belong to one course. How to find to which course a particular student belong?

there is a one to many unidirectional mapping from course to students
#Entity
Course {
#OnetoMany
List<Student> students;
}
#Entity
Student {
name;
age;
}
the database schema looks like
Course
id name duration fee
Student
rollno name age course_id
I am using Jpa repository for getting.
Can anyone please tell how to tell in which course a particular student belong to? Please note that i am not using bi-directioal mapping so student entity class has no reference to course.
Your mappings and DB schema are fine, and there is nothing overly special about your mapping situation - it is just a unidirectional mapping, and there is no need for force mapping it bidirectionally and/or fetching the student data if you don't need it.
JPQL: "Select c from Course c join c.students s where s.name = :name"
With spring boot
#Query("Select c from Course c join c.students s where s.name = ?1")
Course findCourseByStudentName(String name);
Your DB setup would need to be looked at to determine if the Course is unique - I'd guess it isn't, in which case you'll want to return a list of courses that might have this student name registered.
Your problem is in the database deign. No performant code will rescue you from that fate.
Typically there is a join table between Students and Courses that minimally maintains two keys - the studentId and the courseId.
Need to know the courses for a student? Select from the join table where studentId = ‘X’. Need to know students in a course? Select from the join table where courseId = ‘Y’.
I won't comment on the DB design. But solution for this problem is simple.
Basically you need to implement the relationship correctly.
#Entity
public class Course {
private Long id;
#OnetoMany(mappedBy = "course")
List<Student> students;
}
#Entity
public class Student {
private Long id;
private String name;
private Integer age;
#ManyToOne
#JoinColumn(name="course_id")
private Course course;
}
Then simply use the getter
Student student = studentRepo.findStudentById(123);
Course course = student.getCourse();
Here is the full reference: https://www.baeldung.com/hibernate-one-to-many

How to implement subquery in JPA criteria while joining table views to remove duplicates

I was working on an aggregation query where we have two table views with name Task and Member.
For the Member view we can have duplicates. ie: id field of member view is not unique.
So when we do group by to find combinations with task name and an attribute in Member view it won't be working as expected.
In this condition I've formulated a query in SQL to remove duplicates which is added below.
SELECT t.task_name AS task,
m.member_name AS memberName,
Count(*)
FROM task t
JOIN (SELECT DISTINCT id,
member_name
FROM member) m
ON t.member_id = m.id
GROUP BY task,
memberName
Now I want to know how we can convert the JOIN we have used above to JPA criteria API.
Is this query can be done through JPA criteria.
JPA Entities for the same is given below.
Task entity :-
#Entity
#Table(name = "Task")
public class Task {
#Column(name="id")
private Integer id;
.....
#ManyToOne
#JoinColumn(name = "id")
private Member member;
......
}
Member entity :-
#Entity
#Table(name = "Member")
public class Member {
#Column(name="id")
private Integer id;
#Column(name="member_name")
private String name;
......
......
}
If not I would like to know an alternate approach which can ignore duplicates while using GROUP BY clause which can work with JPA as well.
I would really appreciate any help.

hibernate criteria: select object from one table using another one

First of all sorry if my question is't very well formulated.
I have simple object which is mapped to corresponding table:
#Entity
#Table(name = "USERS")
public class User{
#Id
#Column(name = "USER_ID")
#GeneratedValue
private long userId;
#Column(name = "NAME")
private String name;
//getters and setters...
In my database I also have another table. There isn't any associated object with this table but it has column "USER_ID" - the same id as in the "USERS" table.
So the question is, how to select all USERs from the first table which have the same USER_ID as in the second table using Hibernate criteria. For example I have two Users with userId =1 and =2. In second table in column "USER_ID" I have only value "2". So I need only User with userId =2 from the first table.
Your query is classic example of FOREIGN_KEY relation but as u said u don't have Hibernating mapping Model for another table.It's better to use sql-query in your user mapping file
Collect this query result in User object.
Something like this
<sql-query name="userwith">
<return alias="user" class="User"/>
SELECT
user.Name AS {user.name}
FROM USERS
JOIN ANOTHER_TABLE another_table
ON user.ID = another_table.USER_ID
</sql-query>

JPA #ManyToMany join table indexing

Hibernate allows adding indexes on #ManyToOne mappings by the use of #org.hibernate.annotations.Index.
Is there a way to specify index for the join table in a #ManyToMany relation?
If Entity A and Entity B have a #ManyToMany with A being the owning side, the join table will have a composite index (a1, b1).
I wonder if this is enough, or do I need to create another index (b1, a1)?
Answering a 6 year old question here, still relevant though. I came across this question while facing the same issue. Searching the web makes it look like JPA does not support indexes on join tables but it does, this is documented here.
When using #JoinTable you can specify the indexes on the annotation, for example
#ManyToMany()
#JoinTable(name = "car_driver",
joinColumns = #JoinColumn(name = "car_id"),
inverseJoinColumns = #JoinColumn(name = "driver_id"),
indexes = {
#Index(name = "idx_car_driver_car_id", columnList = "car_id"),
#Index(name = "idx_car_driver_driver_id", columnList = "driver_id")
}
)
private Set<Driver> drivers;
I too am searching for this - the holy grail, it seems.
In this post:
How can I ask Hibernate to create an index on a foreign key (JoinColumn)? an answerer seems to believe that adding #Index to the collection creates an index on the join table. It doesn't.
This post:
How do I create an index on join tables using Hibernate annotations? reveals what I am slowly coming to believe is the horrible truth. It's not possible, unless you revert to using an hbm.xml file to define your entities (ie: doesn't appear to be possible using annotations).
So whilst it does speed up queries tremendously to have a composite index on join tables, encompassing both FK columns, but there is currently no way to create said index automatically using annotations.
I am now looking into creating a task to be used after Hibernate's ExportSchema execution to identify join tables and create indexes. It's not going very well! Please do share any viable solutions you happen to come across. I'm hoping someone will share their approach for comparison.
I thought about it and I find solution. In case of many to many relation I used
#ManyToMany
#JoinTable(name = "core_auth_role",
joinColumns = { #JoinColumn(name = "auth_id") },
inverseJoinColumns = { #JoinColumn(name = "role_id") },
uniqueConstraints = { #UniqueConstraint(columnNames = {"role_id", "auth_id" }) })
#ForeignKey(name = "fk_testkey", inverseName = "fk_testkey_inverse")
private Set<Role> roles;
In result I have two idexes (auth_id, role_id) and (role_id, auth_id).
Schema created by Hibernate:
create table SOME_TABLE (
...
primary key (auth_id, role_id),
unique (role_id, auth_id)
);
primary key and unique cosntrainst are automatically indexed in database.
I came across this https://www.baeldung.com/jpa-many-to-many while looking for a way how to have control over the join table, so that I could have at least one of its keys indexed.
It breaks down the many-to-many relation into a many-to-one relation on the join table side and a typical OneToMany on each of the two associated entities, associating them to the join table, like so:
#Entity
class Student {
#OneToMany(mappedBy = "student")
Set<CourseRating> ratings;
}
#Entity
class Course {
#OneToMany(mappedBy = "course")
Set<CourseRating> ratings;
}
#Entity
class CourseRating {
#ManyToOne
#MapsId("student_id")
#JoinColumn(name = "student_id")
Student student;
#ManyToOne
#MapsId("course_id")
#JoinColumn(name = "course_id")
Course course;
}
The #Index annotation can be used on any of the fields in the CourseRating (join table) entity. In my case I used a composite key on the join entity because of reads on its table, so I actually needed to split the relation.
I hope this can be of help.

a simple one -- JPA #OneToMany is generating SQL for table that does not exist

I have a simple JPA project running (with IBM RAD 7.5 on WebSphere 7).
I have a Customer that has many Orders. Looks like this ...
#Entity
public class Customer /* in table CC_CUSTOMER */
#Id
BigDecimal customerId;
#OneToMany(fetch=FetchType.EAGER)
private List<Order> orderList;
...
#Entity
public class Order /* in table CC_ORDER */
#Id
BigDecimal orderId;
Customer customer;
The problem I have is when I try to retrieve a Customer, I get an error because the SQL that's being generated by JPA contains a select for a non-existant table called: CC_CUSTOMER_CC_ORDER
What am I doing wrong?
Thanks!
Rob
You have a missing #ManyToOne annotation at Customer customer; and mappedBy="customer" at #OneToMany annotation
Customer entity
#OneToMany(fetch=FetchType.EAGER, mappedBy="customer")
private List<Order> orderList;
Order entity
#ManyToOne
Customer customer;
Because of that JPA thinks that your relationship is unidirectional and this is solved by join table named CC_CUSTOMER_CC_ORDER. If you let your provider generate the schema the table should be generated.