JPA direct join to entities with common primary key - java

Assume I have dozen of one-to-one relation using common id carId and I can't touch schema or merge them into one.
#Entity
public class Car {
#Id
private Integer id;
#OneToOne(mappedBy="car")
private Registration regist;
#OneToOne(mappedBy="car")
private Detail detail;
#OneToOne(mappedBy="car")
private License license;
}
#Entity
public class Registration {
#OneToOne
private Car car;
private String governor;
}
#Entity
public class Detail {
#OneToOne
private Car car;
private Date manufacturingDate;
}
#Entity
public class License {
#OneToOne
private Car car;
private String licenseNumber;
}
// and more ...
When I create a query begin with License to get data from Detail and Registration, the generated sql looks like
select
car_detail.manufacturing_date,
car_registration.governor
from
car_license
left outer join
car
on car_license.car_id=car.id
left outer join
car_detail
on car.id=car_detail.car_id
left outer join
car
on car_license.car_id=car.id
left outer join
car_registration
on car.id=car_registration.car_id
where
and car_license.licenseNumber=?
It's reasonable because JPA doesn't understand column car_id is common across entities. However, the result is hard to debug and error prone on complicated join.
How can I define those entities so that JPA knowns they don't need additional join on table car and can be joined directly, or just join to table car only once?

Related

Get single element from JPA nested OneToMany relationship

I have those Entities, It is not from real code, but it's not important I think.
#Entity
public class Country{
private String name;
//other fields with getters and setters
#OneToMany
private List<City> cites;
}
#Entity
public class City {
private String name;
//other fields with getters and setters
#OneToMany
private List<Employee> emps;//list size could be millions
}
#Entity
public class Employee {
private String name;
//other fields with getters and setters
#OneToMany
private List<Cars> cars;// list size could be 1000
}
#Entity
public class Car {
private String name;
#ManyToOne
private Employee emp;
}
I would like to get single Car entity but with other data as well(Country, City, Employee) like this
1 Country in which 1 City in which 1 Empoyee in which 1 Car(which Id I put on select)
So when I do jpa joins from Country like
select c from Country c
inner join c.cites ci
inner join ci.emps em
inner join ci.cars car where car.id = ?
I get ALL data in Country(with all cities).
What should I do to get 1 Country,1 City , 1 Employee, 1 Car.
If this is not possible to do with one jpa query then please suggest other way.
All relationships are bidirectional and lazy.
I tried this way.
1)select car by id. then get Id of employee from car.
2)select Employee by id - but at this point Employee data are nulls -
I think it is because ManyToOne from Car to Employee is lazy. What do you think ?
Just select the additional entities you want:
select c, ci, em, car from Country c
inner join c.cites ci
inner join ci.emps em
inner join ci.cars car where car.id = ?
Or, since your associations are bidirectional, select the car: it will have a ManyToOne to its employee, which will have a ManyToOne with its city, which will have a ManyToOne with its country:
select car from Car car where car.id = ?
or simply
em.find(Car.class, carId);
and now you can do
car.getEmployee().getCity().getCountry()
If all of the relationships are bidirectional then I would suggest starting from Car and then fetching up the hierarchy.
select c from Car car
inner join fetch car.emp emp
inner join fetch emp.city city
inner join fetch city.country country
where car.id = ?
Just remember to add that fetch in all of the joins that you missed.

How to create correct entities mapping?

I would like to use ORM Hibernate. And faced with issue below.
There are few tables that have translation on different languages. e.g. it looks like this:
In the database I can use join and get all required data
e.g.:SELECT * FROM car c
JOIN translation t on c.description = t.description
WHERE t.type = 'CAR'
As you can see table 'translation' has column 'type' that uses for filtering by type.
So the main question how to create correct entities and mapping?
A car has OneToMany translations. Similary a city has OneToMany translation.
But every translation has zero to one car or zero to one city.
A translation is either for a Car or a City because its description talks about either City or Car. This is achieved by ManyToOne notation. There is no annotation in hibernate to explicitly say the range from Zero. Following is just to get an Fair Idea of mappings. I am not assuming any relation between City and Car even though I can think city has OneToMany cars.
#Entity
class Car
{
private int Id;
private String name;
//.......... declare all variables that you need
#OneToMany(mappedBy = "car")
private List<Translation>
//getters and setters
}
#Entity
class City
{
private int Id;
private String name;
//.......... declare all variables that you need
#OneToMany(mappedBy = "city")
private List<Translation>
//getters and setters
}
#Entity
class Translation
{
private int Id;
private String language;
//.......... declare all variables that you need
#ManyToOne
private Car;
#ManyToOne
private City;
//getters and setters
}

How to filter by attributes of attributes of an Entity class in Hibernate

I'm using Hibernate in Java to map classes to DB tables. I have a Person table, each entry has many Pets, each of which has many Toys.
I'd like to be able to filter these in my DAO based on attributes of the toys; for example, find all people with pets that have red toys, as a List<Person>. How can I filter on this?
Person class:
#Entity
public class Person {
...
#OneToMany(mappedBy = "person")
private List<Pet> pets;
...
}
Pet class:
#Entity
public class Pet {
...
#OneToMany(mappedBy = "pet")
private List<Toy> toys;
...
}
Toy class:
#Entity
public class Toy {
...
private String colour;
...
}
I am not sure what you mean 'filter' in this case, but you can always use HQL.
For example:
select p from Person p
inner join p.pets as pets
inner join pets.toys as toys
where p.pets.size() > 0
and toys.color = 'red'
Maybe where condition 'p.pets.size() > 0' is redunant here, because of inner join.

How to get child table rows using parent table ID?

I have two tables: Organization(Parent) and Department(Child).
There is One to Many relationship, and is mentioned in Organization table only.
#Entity
#Table(name="TBL_STD_ORGANIZATION")
public class Organization implements Serializable {
#Id
#GeneratedValue
#Column(name="FLD_ORG_ID")
private Long organizationId;
#Column(name="FLD_ORG_NAME")
private String orgName;
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private java.util.List<Department> listOfDepartMents = new java.util.ArrayList<Department>();
}
Below is Department Class:
#Entity
#Table(name="TBL_STD_DEPARTMENT")
public class Department implements Serializable {
#Id
#GeneratedValue
#Column(name = "FLD_DEPARTMENT_ID")
private Long departmentId;
#Column(name = "FLD_DEPARTMENT_NAME")
private String departmentName;
}
I wrote relationship in Parent table, because of it hibernate creates third table.
Now, I have to retrieve departments start with "sa" keyword and in specific organization.
So I want the HQL or SQL query query. I am not getting it how to write such complex query.
Any suggestions?
I'm fairly certain the HQL/JPQL would be:
SELECT d FROM Organization o JOIN o.listOfDepartMents d WHERE d.departmentName LIKE "sa%"

Hibernate generating a query from Named Query that joins on the wrong column?

I am using named query (hibernate 4).Entity defined as below.
#Entity
#NamedQuery(
name = "findAllProduct",
query = "SELECT PC.pincode,PO.description"
+" FROM PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION PVPOL"
+" INNER JOIN PVPOL.paymentId PID"
+" INNER JOIN PVPOL.pincode PC"
+" INNER JOIN PVPOL.paymentOptions PO"
+" where PVPOL.id = :id"
)
public class PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION extends baseEntity.Entity {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column(name="Payment_Id")
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,mappedBy="id")
private Set<Product_Catalog_Vendor> paymentId;
#Column(name="pincode_id")
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,mappedBy="pincode_id")
private Set<Pincodes> pincode;
#Column(name = "payment_options")
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,mappedBy="paymentOptions")
private Set<Payment_Options> paymentOptions;
//Protected setter getter here
}
Hibernate generating below sql:-
select pincode2_.pincode as col_0_0_, paymentopt3_.Description as col_1_0_
from PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION product_ve0_
inner join Product_Catalog_Vendor paymentid1_
on product_ve0_.id=paymentid1_.Id
inner join Pincodes pincode2_
on product_ve0_.id=pincode2_.pincode_id
inner join payement_options paymentopt3_
on product_ve0_.id=paymentopt3_.payment_options
where product_ve0_.id=?
Instead of
select pincode2_.pincode as col_0_0_, paymentopt3_.Description as col_1_0_
from PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION product_ve0_
INNER JOIN product_catalog_vendor paymentid1_
ON **product_ve0_.payment_id = paymentid1_.id**
INNER JOIN PINCODES pincode2_
ON **product_ve0_.pincode_id = pincode2_.pincode_id**
INNER JOIN payement_options paymentopt3_
ON **product_ve0_.payment_options=paymentopt3_.payment_options**
where product_ve0_.id=1;
Product_catalog_vendor class:
#Entity
public class Product_Catalog_Vendor extends baseEntity.Entity {
#Id
#Column(name="Id")
private int id ;
//Setters and getters here
}
Pincodes Entity:
#Entity
public class Pincodes extends baseEntity.Entity {
#Id
private int pincode_id;
#Column(name="pincode")
private int pincode;
//Setters and getters here
}
payment_options Entity below:
#Entity
#Table(name="payement_options")
public class Payment_Options extends baseEntity.Entity {
#Id
#Column(name="payment_options")
private int paymentOptions;
//Setter getter
}
I have searched on many sites but unable to find the cause behind the scene. Please give me suggestions if i am doing something wrong. some good references would be appreciated. Thanks
just to get your problem correcty, your query joins on paymentid1_.Id instead of paymentid1_.id? or am I missing the differenz between the expected and the real query?
I'm not a pro but just guessing I would say your query is joining to the id of the Product_Catalog_Vendor:
#Id
#Column(name="Id")
private int id ;
so because thats why its Id and not id...
I think you don't need mappedBy at all due to unidirectional mapping or,anyway ,you are using them in a weird way.
mappedBy is necessary only if association is bidirectional (not your case) and should refers to a field which type is of the same type of entity where mappedBy is declared (and not a String type like in your case).You used mappedBy in a way like referencedColumnName property
In your example:
#Entity
public class Product_Catalog_Vendor extends baseEntity.Entity {
#ManyToOne
private PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION pvpol;
}
and
public class PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION extends baseEntity.Entity {
#Column(name="Payment_Id")
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,mappedBy="pvpol")
private Set<Product_Catalog_Vendor> paymentId;
}

Categories