I know the problem with N+1 select is well-known, but trying using different fetching strategies does not help to avoid it when I use native query.
I have 2 entities: A and B that correspond to the mysql tables A and B.
Several rows in table A could have the same b_id, that's why I use #ManyToOne annotation.
#Entity
#Table(name = "A")
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(FetchMode.JOIN)
private B b;
}
I also create entity B.
#Entity
#Table(name = "B")
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String url;
}
I need to find all rows in A that are linked only for 1 row in table B. So I create native query in my ARepository
public interface ARepository extends JpaRepository<A, Integer> {
#Query(value = "SELECT a.id, a.b_id, a.name, b.url "
+ "FROM a "
+ "JOIN b ON a.b_id = b.id "
+ "GROUP BY a.b_id "
+ "HAVING count(a.b_id) = 1, nativeQuery = true)
List<A> getLinkedOnce();
But when when I run my restcontroller that just call getLinkedOnce method from repository, I see that in console, 1-st my query is called, then there are number of selects for each row in A that are end with
from B b0_ where b0_.id=?
I try to use different approaches, LAZY, EAGER and it does not work. I think because there is a usage of native query. But maybe the reason is another.
Related
I have the following (simplified) entities:
#Table(name = "groups")
public class Group {
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#ManyToMany(fetch = FetchType.LAZY)
private Set<User> users;
...
}
#Table(name = "users")
public class StoredUser extends StoredBase {
#Column(name = "id")
private long id;
#Column(nullable = false, unique = true)
private String username;
#ManyToMany(mappedBy = "users")
private Set<Group> groups;
...
}
So I wanted to get something like list of username group by groupId:
group_id group_name username
--- --- ----
1 gr1 1, 2, 3
2 gr2 4, 5
3 gr3 1, 4
At first I was just using groupRepository.findAll() and convert the response based on that. But the amount of unrelated data coming with Group and User is big and is slowing down the response. So I want to fetch just the related values only.
So I wonder what is the best way to achieve this?
Many thanks
group_concat and a 'group by' should get you there.
Something like (untested, but someone will be along to tell me if I'm being fick):
select g.group_id, g.group_name, group_concat(u.username) as all_users
from groups as g join users as u on g.users = u.id
group by u.id;
You can use projections from Spring Data JPA (doc). In your case, create interface:
interface GroupAndUsers{
String getId();
String getName();
Set<Integer> getUsersId();
}
and add following method to your repository:
List<GroupAndUsers> findAllGroupAndUsers();
I have a parent table and a child table where I am only getting 1 record from child table but not getting case insensitive matched record which is a mixed string. I am expecting it should return 2 records.
Below is the code for the same.
//parent Table
#Entity
#Table(name = "employee")
public class Employee implements Serializable {
#Id
#Column(name = "employeeID")
private String employeeID;
#Column(name = "name_first")
private String nameFirst;
#Column(name = "name_last")
private String nameLast;
}
//Child Table
#Entity
#Table(name = "employee_salary")
public class EmployeeSalary implements Serializable {
#EmbeddedId
private EmployeeSalaryPK employeeSalaryPKCompositeKey;
#Column(name = "salaryBracket")
private String salaryBracket;
}
#Embeddable
public class EmployeeSalaryPK implements Serializable {
#Column(name = "employeeID")
private String employeeID;
#Column(name = "salary")
private String salary;
}
In employee_salary table I have two records (as shown below) but while fetching it using HQL only one record is coming with an actual match but case insensitive record is not coming.
Employee Record:- ABC John Kramer
employee_salary table record:-
ABC 100900
aBc 76770
I am using simple HQL query (see below code) but getting only first record whenever I want to get both record as employeeID is abc.
String hqlQuery = " FROM " + Employee.class.getName() + " E WHERE E.employeeID= :EMPLOYEEID";
Session session = entityManager.unwrap(Session.class);
List<?> responseList = session.createQuery(hqlQuery).setParameter("EMPLOYEEID", "ABC").list();
To get all entities by case insensetive String id you have to convert id to same case (lowercase or uppercase) on both sides of the WHERE clause equality operator
String hqlQuery = " FROM " + Employee.class.getName() + " E WHERE lower(E.employeeID) = :EMPLOYEEID";
Session session = entityManager.unwrap(Session.class);
List<?> responseList = session.createQuery(hqlQuery).setParameter("EMPLOYEEID", "ABC".toLowerCase()).list();
I've got this entity:
#Getter
#Setter
#NoArgsConstructor
#ToString
#Accessors(chain = true)
#Entity
#Table(name = "offer_categs")
public class OfferCateg {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#Nullable
private String image;
#ManyToOne
#JoinColumn(name = "parent_id")
private OfferCateg parent;
#OneToMany(mappedBy = "parent",
cascade = CascadeType.REMOVE,
fetch = FetchType.LAZY,
orphanRemoval = true)
private Set<OfferCateg> children;
}
I'm trying to just create categories and subcategories. My problem is that when using the below method, parent_id might be null in case of a root category. How can I make the query to allow for that? I can't use IS NULL. Should I make two queries and be careful of the calling parent_id value ?
#Query(value = "SELECT * FROM offer_categs oc WHERE oc.parent_id = ?1 AND oc.name = ?2", nativeQuery = true)
OfferCateg findByNameAndParent(#Nullable Long parentId, String name);
EDIT
I changed the query to this and it seems to be working
#Query(value = "SELECT * FROM offer_categs oc WHERE " +
"(oc.parent_id = ?1 AND oc.name = ?2) OR" +
"(oc.parent_id IS NULL AND ?1 IS NULL AND oc.name = ?2)",
nativeQuery = true)
OfferCateg findByNameAndParent(#Nullable Long parentId, String name);
BUT...isn't this overkill ?! I'm sure it can be done more easily.
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
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.