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

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.

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.

Eclipselink Shared Cache - Lazy associations

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

How to avoid unnecessary inner join on a simple query on entity inheritance mapped with JOINED strategy?

I'm using JPA 2 with Hibernate 4.2.0-Final as provider and I have the following entities:
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
public class Person {
#Id
private String id;
.. Person attributes ..
.. Getters/Setters ..
}
#Entity
#Table(uniqueConstraints={#UniqueConstraint(name="UniqueCode", columnNames="code")})
public class Customer extends Person {
#Column(nullable=false)
private String code;
.. Other Customer attributes ..
.. Getters/Setters ..
}
And I have the following JPQL:
SELECT count(distinct c.code) FROM Customer c
For which Hibernate is generating the following SQL:
select
count(distinct customer0_.code) as col_0_0_
from
Customer customer0_
inner join
Person customer0_1_
on customer0_.id=customer0_1_.id
But I only need to count Customers with distinct code, which happens to be a field that is specific to Customer, so there is no need for the inner join to 'Person'. I'd like Hibernate to generate the SQL like follows (i.e. without joinning table 'Person'):
select
count(distinct customer0_.code) as col_0_0_
from
Customer customer0_
Is there a way to tell Hibernate to avoid the unnecessary inner join? Maybe some Hibernate-specific Query Hint?
The JOINED Strategy in JPA uses a separate table for each class in the object hierarchy.
So if you want to load objects for a subclass you also have to load information from the parent class (As the subclass alone does not represent complete picture without the attributes in the parent class). This results in a JOIN when querying for the sub-object.
From the JPA documentation you can see this as being a main disadvantage for The JOINED strategy.
1) Aside from certain uses of the table-per-class strategy described
below, the joined strategy is often the slowest of the inheritance
models. Retrieving any subclass requires one or more database joins,
and storing subclasses requires multiple INSERT or UPDATE statements.

Is it possible to optimize SQL Generated by Hibernate for OneToMany relationship with JoinTable?

I'm using JPA with Hibernate 4 as provider and I have the following entities:
#Entity
public class Customer {
#Id
private String id;
private String name;
#OneToMany(cascade=CascadeType.ALL)
#JoinTable(name="customers_phones",
joinColumns={#JoinColumn(name="id_customer")},
inverseJoinColumns={#JoinColumn(name="id_phone")}
)
private List<Phone> phones;
.. Getters/Setters ..
}
#Entity
public class Phone {
#Id
private String id;
private String number;
.. Getters/Setters ..
}
And I have the following JPQL:
SELECT c FROM Customer c INNER JOIN c.phones p WHERE p.id = :phone
For which Hibernate is generating the following SQL:
select
customer0_.id as id1_0_,
customer0_.name as name2_0_
from
Customer customer0_
inner join
customers_phones phones1_
on customer0_.id=phones1_.id_customer
inner join
Phone phone2_
on phones1_.id_phone=phone2_.id
where
phone2_.id=?
I'd like Hibernate to generate the SQL like follows (i.e. without joinning table 'Phone'):
select
customer0_.id as id1_0_,
customer0_.name as name2_0_
from
Customer customer0_
inner join
customers_phones phones1_
on customer0_.id=phones1_.id_customer
where
phones1_.id_phone=?
I know I could map a new entity to the join table 'customers_phones' associate it to Customer and use it in the query or I could use native SQL instead of JPQL, but I was wondering if there is a better way to achieve this (without changing entity model and still using JPQL), maybe some Hibernate-specific Query Hint?