JPA Hibernate Nested Objects - mysql

Basically I have 3 tables: COUNTRY, STATE and CITY.
in Country.java:
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "COUNTRY_ID")
private List<State> state = new Vector<State>();
in State.java
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "STATE_ID")
private List<City> city = new Vector<City>();
JPA query looks like:
caEntityManager.createQuery("SELECT C FROM COUNTRY C
JOIN fetch C.STATE S JOIN fetch S.CITY").getResultList();
When I try to execute the query I get:
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
I am sure my query is wrong, i am new to this, please appoint me to the right direction. I
Thanks!

Problem is Hibernate can not fetch two bags EAGERly. The quick solution would be to change the Lists to Sets.
To read more:
Article 1
Article 2
Also this question suggests a couple of other solutions.

Related

JpaRepository custom #Query generates unwanted CROSS JOIN

account entity code:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
#NotFound(action = NotFoundAction.IGNORE)
private User user;
user entity code:
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Account> account = new ArrayList<>();
the repository cusotom method query annotion
#Query(value = "FROM Account a WHERE (:userId IS NULL Or a.user.id = :userId))
It generates this query:
from account account0_ cross join user user1_ where account0_.user_id=user1_.id and (? is null or user1_.id=?)
It worked fine before I updating springboot from 2.1.4.release to 2.6.5
which is expected to be the following:
from account account0_ WHERE (:userId IS NULL Or account0_.user_id = :userId)
Don't know if it's due to the version change or not.
Can someone give some clues?
It's a stange behavior on JPA if you use
#NotFound(action = NotFoundAction.IGNORE)
this above annotion,
remove this will behave normally.

Many to many Jpa Query Spring boot

I have three mysql tables with a many to many relationship and I am trying to make a Jpa Query on spring boot. The tables are
product with fields id, name
extra with fields id, name
product_extra with fields id, product_id, extra_id
Product table has a many to many relationship with extra table, as a product can have many extras hence the need for product_extra table
Here is the query i would like to include in my project
SELECT extra.name
FROM extra
INNER JOIN product_extra ON extra_id = extra.id
WHERE product_id = ?;
Should i have like a #ManyToMany annotation and where should i have it
Yes you should. Use #ManyToMany to map between Product and Extra.Make sure to use Set instead of List for the mapping in order to have better performance. It looks like:
#Entity
#Table(name="product")
public class Product{
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE})
#JoinTable(name = "product_extra",
joinColumns = #JoinColumn(name = "product_id"),
inverseJoinColumns = #JoinColumn(name = "extra_id")
)
private Set<Extra> extras = new HashSet<>();
}
#Entity
#Table(name="extra")
public class Extra{
#ManyToMany(mappedBy = "extras")
private Set<Product> products = new HashSet<>();
}
After mapping them , you can then use JPQL to get a product by id together with its extra by :
select p from Product p left join fetch p.extras where p.id = :productId;

Selecting where an entity contains a list which elements have another list

I am writing a JPQL query in spring JPA and i have the following scenario. I have a entity Margin which contains a list of PerPeriodMargin and each element of PerPeriodMargin contains a list of MarginFactor.
code:
#Entity
public class Margin {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "margin", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PerPeriodMargin> perPeriodMargins;
}
#Entity
public class PerPeriodMargin{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
private Margin margin;
#OneToMany(mappedBy = "perPeriodMargin", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MarginFactor> marginFactors;
}
#Entity
public class MarginFactor{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
private Underlying underlying;
#ManyToOne
private PerPeriodMargin perPeriodMargin;
}
I would like to select all Margin where MarginFactor underlying.id is passed as a parameter in a single jpql query?
Any suggestions?
i activated hibernate logging by this line in application.properties "logging.level.org.hibernate.SQL=DEBUG" and i have been confused about the generated SQL queries. its seems there is something wrong about that multiple join. can any one explain this.
select * from margin m inner join per_period_margin ppm on m.id = ppm.margin_id join margin_factor mf on ppm.id = mf.per_period_margin_id where mf.underlying_id = ? and m.id = (select margin_id from trading_account ta where ta.id = ?)
and on for perPeriodMargin
select perperiodm0_.margin_id as margin_i5_12_0_, perperiodm0_.id as id1_12_0_, perperiodm0_.id as id1_12_1_, perperiodm0_.end_time as end_time2_12_1_, perperiodm0_.margin_id as margin_i5_12_1_, perperiodm0_.name as name3_12_1_, perperiodm0_.start_time as start_ti4_12_1_ from per_period_margin perperiodm0_ where perperiodm0_.margin_id=?
until now all is seams good.
finally ther are two other queries that try to get marginFactors.
select marginfact0_.per_period_margin_id as per_peri6_9_0_, marginfact0_.id as id1_9_0_, marginfact0_.id as id1_9_1_, marginfact0_.bid as bid2_9_1_, marginfact0_.notional as notional3_9_1_, marginfact0_.offer as offer4_9_1_, marginfact0_.per_period_margin_id as per_peri6_9_1_, marginfact0_.settlement as settleme5_9_1_, marginfact0_.underlying_id as underlyi7_9_1_, underlying1_.id as id1_24_2_, underlying1_.digits as digits2_24_2_, underlying1_.display as display3_24_2_, underlying1_.enable as enable4_24_2_, underlying1_.enable_buy as enable_b5_24_2_, underlying1_.enable_sell as enable_s6_24_2_, underlying1_.focus_digits as focus_di7_24_2_, underlying1_.focus_position as focus_po8_24_2_, underlying1_.left_currency_id as left_cu11_24_2_, underlying1_.name as name9_24_2_, underlying1_.right_currency_id as right_c12_24_2_, underlying1_.temporary_disable as tempora10_24_2_, currency2_.id as id1_3_3_, currency2_.digits as digits2_3_3_, currency2_.enable_buy as enable_b3_3_3_, currency2_.enable_sell as enable_s4_3_3_, currency2_.name as name5_3_3_, currency2_.symbol as symbol6_3_3_, currency2_.temporary_disable as temporar7_3_3_, currency3_.id as id1_3_4_, currency3_.digits as digits2_3_4_, currency3_.enable_buy as enable_b3_3_4_, currency3_.enable_sell as enable_s4_3_4_, currency3_.name as name5_3_4_, currency3_.symbol as symbol6_3_4_, currency3_.temporary_disable as temporar7_3_4_ from margin_factor marginfact0_ left outer join underlying underlying1_ on marginfact0_.underlying_id=underlying1_.id left outer join currency currency2_ on underlying1_.left_currency_id=currency2_.id left outer join currency currency3_ on underlying1_.right_currency_id=currency3_.id where marginfact0_.per_period_margin_id=?
and as we see here in the last query there are only one where condition on perPeriodmarginId. as I think it must also contain underlying condition, because this query is the responsible of fetching marginFactors where we must extract the data that who have a specific underlyingId.
I'm really serious about this question please can someone explain that or is it a bug in hibernate!
This is the query:
select m
FROM Margin m
JOIN m.perPeriodMargins ppm
JOIN ppm.marginFactors mf
JOIN mf.underlying und
WHERE und.id = :id

Hibernate HQL query get data from table associated with another table

I have an entity called Locality as:-
#Entity
#Table(name = "CMN_LOCALITY_MASTER")
public class Locality {
#Id
#Column(name = "LOCALITY_ID", unique = true, nullable = false,length = 11)
#GeneratedValue(strategy = GenerationType.IDENTITY)
int localityId;
#Column(name = "LOCALITY_DESCRIPTION",length=70)
String localityDescription;
#JsonProperty(access = Access.WRITE_ONLY)
#ManyToOne
#JoinColumn(name = "PINCODE_ID")
Pincode pinCode;
#JsonIgnore
#ManyToOne
City city;
}
which contains another entity called City and Pincode.
City is as below:-
#Entity
#Table(name = "CMN_CITY_MASTER")
public class City{
#Id
#Column(name = "CITY_ID", unique = true, nullable = false,length = 11)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int cityId;
#Column(name = "CITY",length = 150)
private String description;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "STATE_ID")
private State state;
}
I want to Get all data from Locality entity/table which has City ID = (e.g. 1)
I tried below queries:-
#Query("SELECT a FROM Locality a INNER JOIN a.city c WHERE c.cityId=?1")
List<Locality>getAllLocalityByCity(int cityId);
and also
#Query("SELECT a FROM Locality a WHERE a.city.cityId=?1")
List<Locality>getAllLocalityByCity(int cityId);
But these are not working.
Could you please suggest me something/way to query the data?
Also, is there an Eclipse Plug-In/Tool to test HQL queries in a faster way than restarting the server for every change in the query?
Could you also suggest reading documents/book for learning HQL?
Since you are not providing any logs or explanation I can suggest you try the following:
#Query("SELECT a FROM Locality a INNER JOIN a.city c WHERE c.cityId = :cityId")
List<Locality>getAllLocalityByCity(#Param("cityId") int cityId);
For learning the HQL I would start with Hibernate Docs. You can take a look at Criteria API as well.

Hibernate criteria example query gets multiple records

I have a generic criteria query and it returns same records. I think there is something wrong with my student save method. Here is my save method;
Student student = new Student();
student.setId(Utility.generateUUID());
student.setClassroom(selectedClassroom);
student.setUrl(urlAddress);
genericService.save(student);
When I try to get all Classrooms from datatable it returns 3 Classroom object which are same but there is only one record in Classroom table. The Problem is there are 3 student records which Classrooms are referencing to this classroom record.
My criteria query;
#Transactional(readOnly = true)
public <T> List<T> getByTemplate(T templateEntity) {
Criteria criteria = getCurrentSession().createCriteria(templateEntity.getClass());
criteria.add(Example.create(templateEntity));
return criteria.list();
}
Entities;
public class Classroom{
....
#OneToMany(mappedBy = "classroom", fetch = FetchType.EAGER)
private List<Student> studentList;
}
public class Student{
#JoinColumn(name = "classroom", referencedColumnName = "id")
#ManyToOne(fetch = FetchType.LAZY)
private Classroom classroom;
}
Try to add the following to your criteria:
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
This will retrieve distinct entities for Classroom even tought the inner join select will retrieve the three lines (one per user).