Hibernate Criteria Left Excluding JOIN - java

I have no ideas how to do it using Hibernate Criteria
SELECT *
FROM Table_A A
LEFT JOIN Table_B B
ON A.Key = B.Key
WHERE B.Key IS NULL
there is Hibernate mapping like
#Entity
class A{
#Id
#Column(name = "ID")
private String ID;
... // fields
}
#Entity
class B{
... // fields
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "A_ID", referencedColumnName = "ID")
#Cascade(CascadeType.DETACH)
private A a;
... // fields
}
So I need to get list of all A which are not referred by B

Not tried it before, but something like this should work:
select * from Table_A a
where a not in (
select b.a from Table_B b )
This is of course in HQL
Criteria might look like this:
DetachedCriteria subquery = DetachedCriteria.forClass(B.class)
.setProjection( Property.forName("a.ID") )
.add(Restrictions.isNotNull("a.ID"));
session.createCriteria(A.class)
.add ( Property.forName("ID").notIn(subquery) )
.list();

Related

How to fetch join nested entities in JPA-eclipselink, in case of sub-entity being in relation #ManyToOne

I have multiple entities that i want to fetch in single query, because N+1 queries last too long.
For example SQL join query lasts 5 seconds on DB, but elcipselink persistence fetching lasts 50-80 seconds due to N+1 fetching.
I found out that LEFT JOIN FETCH is not working as soon as #ManyToOne relation is implemented.
Does anyone know solution to LEFT JOIN FETCH for this case?
Please find below simplified entities.
#Entity
#Table(name="SITUATION_DATA")
#NamedQuery(name="SituationData.findAll", query="SELECT s FROM SituationData s")
public class DatexSituationData implements Serializable {
private static final long serialVersionUID = 1L;
//bi-directional many-to-one association to SituationRecord
#OneToMany(mappedBy="datexSituationData", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
#JoinFetch(value=JoinFetchType.OUTER)
private List<SituationRecord> situationRecords;
}
#Entity
#Table(name="SituationRecord")
#NamedQuery(name="SituationRecord.findAll", query="SELECT s FROM SituationRecord s")
public class SituationRecord implements Serializable {
private static final long serialVersionUID = 1L;
#OneToMany(mappedBy="situationRecord", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
#JoinFetch(value=JoinFetchType.OUTER)
private List<SituationRecordComment> situationRecordComment;
#OneToMany(mappedBy="situationRecord", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
#JoinFetch(value=JoinFetchType.OUTER)
private List<SituationRecordTypeElement> situationRecordTypeElements;
//bi-directional many-to-one association to SituationLocation
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
#JoinFetch(value=JoinFetchType.OUTER)
#JoinColumn(name="ID_LOKACIJE")
private SituationLocation situationLocation;
//bi-directional many-to-one association to DatexSituationData
#ManyToOne()
#JoinColumns({
#JoinColumn(name="SITUATION_ID", referencedColumnName="ID", nullable=false),
#JoinColumn(name="SITUATION_VERSION", referencedColumnName="VERSION", nullable=false)
})
private DatexSituationData datexSituationData;
}
#Entity
#Table(name="SITUATION_LOCATIONS")
#NamedQuery(name="SituationLocation.findAll", query="SELECT s FROM SituationLocation s")
public class SituationLocation implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="situation_location_seq")
#SequenceGenerator(name="situation_location_seq", sequenceName="SEQ_SITUATION_LOCATION", allocationSize=1)
#Column(name="ID_LOKACIJE", unique=true, nullable=false)
private long idLokacije;
//bi-directional many-to-one association to SituationRecord
#OneToMany(mappedBy="situationLocation", cascade = CascadeType.PERSIST)
private List<SituationRecord> situationRecords;
}
This is how i fetch it.
I have tried all of the below combinations, but every combinations makes query for each row (object) in SituationData, or in some cases for each joined SituationData join SituationRecord.
String sQuery =
//"select * from SITUATION_DATA t";
//"SELECT * FROM (select t.*, rank() over(partition by t.id order by version desc) rnk from SITUATION_DATA t) where rnk = 1";
"SELECT ds FROM SituationData ds LEFT JOIN FETCH ds.situationRecords sr LEFT JOIN FETCH sr.situationLocation sl LEFT JOIN FETCH sr.situationRecordTypeElements sre LEFT JOIN FETCH sr.situationRecordComment src";
EntityManager em = Emf.getInstance().getFactory().createEntityManager();
//Query q = em.createNativeQuery(sQuery, DatexSituationData.class);
Query q = em.createQuery(sQuery, DatexSituationData.class);
// q.setHint("eclipselink.LEFT_FETCH", "t.situationRecords.situationRecordComment");
q.setHint("eclipselink.LEFT_FETCH", "ds.sr.sl");
q.setHint("eclipselink.LEFT_FETCH", "ds.sr.sre");
q.setHint("eclipselink.LEFT_FETCH", "ds.sr.src");
// q.setHint("eclipselink.JDBC_FETCH_SIZE", "100");
lResult = q.getResultList();
Since you are not explicitly state EclipseLink version being used, I'll just assume version 2.6.
As per the official EclipseLink documentation, eclipselink.LEFT_FETCH is not a supported query hint. You are probably trying to use eclipselink.join-fetch or eclipselink.left-join-fetch as documented here.
The proper way to use this hint is along the lines of:
String sQuery = "SELECT ds FROM DatexSituationData ds";
EntityManager em = emf.getInstance().getFactory().createEntityManager();
TypedQuery q = em.createQuery(sQuery, DatexSituationData.class);
q.setHint("eclipselink.join-fetch", "ds.situationRecords");
q.setHint("eclipselink.join-fetch", "ds.situationLocation");
// ...
lResult = q.getResultList();
Another approach would be batch fetching.
This would work as:
//...
em
.createQuery("SELECT ds FROM DatexSituationData ds")
.setHint("eclipselink.batch", "ds.situationRecords")
//...
.setHint("eclipselink.batch.type", "IN")
.setHint("eclipselink.batch_size", "1000");
//...
You would probably test both approaches and gather some metrics; then decide which one works better (in terms of performance) for your DB schema and usage patterns.

How to prevent JPA query related entity

Firstly, let me thank to who want to give the answer,
I am a new person using JPA for now, suppose that I have two tables, table A and B, for table A, we have the column
id_A,
id_B,
etc...
For table B, we have
id_B
And we have the entity classes,
#Data
class A {
#Id
#Column(name = "ID_A")
private String id;
#ManyToOne
#JoinColumn(name = "ID_B", referencedColumnName = "ID_B")
private B b;
}
#Data
class B {
#Id
#Column(name = "ID_B")
private String id;
#JsonManagedReference
#OneToMany(mappedBy = "b", cascade = CascadeType.ALL)
#BatchSize(size = BATCH_SIZE)
private List<A> as;
}
Now, in order to only use the id of B, I firstly select all the relevant entity of A by ARepository.findAllByIds().
with the above query, I want to get all the ID_Bs, but when I do it by looping the result of the above query - a.getB, I noticed that it will get the B from Database again.
I know that we can fetch the A and B together by EAGER or EntityGraph, etc...
I am just wondering, is there any a way that I can only get the id_b from the ARepository.findAllByIds()?
To answer your question I think you will have to annotate your findAllByIds method with something like...
#Query(value = "SELECT a, b.id FROM A a LEFT JOIN a.b b where a.id in :ids") then your Bs will be loaded within the same query as the As

How to avoid unwanted queries with Hibernate?

I want to make a query against an entity , called Utilisateur :
#Override
#Transactional
public List<Utilisateur> list() {
String hql = "from Utilisateur where deleted is null or deleted <> 1";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
#SuppressWarnings("unchecked")
List<Utilisateur> listUser = (List<Utilisateur>) query.list();
return listUser;
}
#Entity
#Table(name = "utilisateur")
public class Utilisateur {
#Id
#SequenceGenerator(name="s_utilisateur", sequenceName="s_utilisateur", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="s_utilisateur")
#Column(name = "user_code")
private Long code;
#Column(name = "user_nom")
private String nom;
#Column(name = "user_prenom")
private String prenom;
#Column(name = "user_login")
private String login;
#ManyToOne
#JoinColumn(name = "struct_code")
private Structure structure;
...
}
As you can see there is the attribute structure of type Structure. So here is the entity Structure :
#Entity
#Table(name = "structure")
public class Structure {
#Id()
#Column(name="struct_code")
private String code;
#ManyToOne
#JoinColumn(name = "str_struct_code")
private Structure parent;
#ManyToOne
#JoinColumn(name="niv_struct_code")
private NiveauStructure niveauStructure;
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "structures")
#JsonBackReference
private Set<Cdmt> programmes = new HashSet<Cdmt>();
#Column(name="struct_lib")
private String lib;
...
}
Again there is the attribute programmes , here is its code :
#Entity
#Table(name = "cdmt")
public class Cdmt {
#Id
#Column(name = "cdmt_code")
private String code;
#ManyToOne
#JoinColumn(name = "class_cdmt_code")
private ClasseCdmt classeCdmt;
#Column(name="cdmt_design")
#Lob
private String lib;
#ManyToOne
#JoinColumn(name = "prog_code")
private Pmo pmo;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
#JoinTable(name = "programme_structure" , joinColumns = {#JoinColumn(name = "cdmt_code")} , inverseJoinColumns = {#JoinColumn(name = "struct_code")} )
#JsonManagedReference
private Set<Structure> structures = new HashSet<Structure>();
#ManyToOne
#JoinColumn(name = "cdm_cdmt_code")
private Cdmt cdmtParent;
...
}
At runtime there are many queries involved displayed in the console , among those queries there are queries against the Pmo entity although there is no mention about that entity in the query ! So how to avoid this propagations of queries ?
update :
here is query trace in the console :
Hibernate: select programmes0_.struct_code as struct_code2_50_0_, programmes0_.cdmt_code as cdmt_code1_33_0_, cdmt1_.cdmt_code as cdmt_code1_4_1_, cdmt1_.cdm_cdmt_code as cdm_cdmt_code7_4_1_, cdmt1_.cdmt_comment as cdmt_comment2_4_1_, cdmt1_.class_cdmt_code as class_cdmt_code8_4_1_, cdmt1_.cdmt_debut as cdmt_debut3_4_1_, cdmt1_.deleted as deleted4_4_1_, cdmt1_.cdmt_fin as cdmt_fin5_4_1_, cdmt1_.cdmt_design as cdmt_design6_4_1_, cdmt1_.prog_code as prog_code9_4_1_, cdmt2_.cdmt_code as cdmt_code1_4_2_, cdmt2_.cdm_cdmt_code as cdm_cdmt_code7_4_2_, cdmt2_.cdmt_comment as cdmt_comment2_4_2_, cdmt2_.class_cdmt_code as class_cdmt_code8_4_2_, cdmt2_.cdmt_debut as cdmt_debut3_4_2_, cdmt2_.deleted as deleted4_4_2_, cdmt2_.cdmt_fin as cdmt_fin5_4_2_, cdmt2_.cdmt_design as cdmt_design6_4_2_, cdmt2_.prog_code as prog_code9_4_2_, classecdmt3_.class_cdmt_code as class_cdmt_code1_5_3_, classecdmt3_.class_cdmt_comment as class_cdmt_comment2_5_3_, classecdmt3_.class_cdmt_lib as class_cdmt_lib3_5_3_, classecdmt3_.class_cdmt_niveau as class_cdmt_niveau4_5_3_, pmo4_.prog_code as prog_code1_31_4_, pmo4_.class_pmo_code as class_pmo_code6_31_4_, pmo4_.prog_debut as prog_debut2_31_4_, pmo4_.prog_fin as prog_fin3_31_4_, pmo4_.prog_design as prog_design4_31_4_, pmo4_.pmo_prog_code as pmo_prog_code7_31_4_, pmo4_.pnd_code as pnd_code8_31_4_, pmo4_.prog_comment as prog_comment5_31_4_, classepmo5_.class_pmo_code as class_pmo_code1_6_5_, classepmo5_.class_pmo_comment as class_pmo_comment2_6_5_, classepmo5_.class_pmo_lib as class_pmo_lib3_6_5_, classepmo5_.class_pmo_niveau as class_pmo_niveau4_6_5_, pmo6_.prog_code as prog_code1_31_6_, pmo6_.class_pmo_code as class_pmo_code6_31_6_, pmo6_.prog_debut as prog_debut2_31_6_, pmo6_.prog_fin as prog_fin3_31_6_, pmo6_.prog_design as prog_design4_31_6_, pmo6_.pmo_prog_code as pmo_prog_code7_31_6_, pmo6_.pnd_code as pnd_code8_31_6_, pmo6_.prog_comment as prog_comment5_31_6_, pnd7_.pnd_code as pnd_code1_32_7_, pnd7_.creation as creation2_32_7_, pnd7_.pnd_debut as pnd_debut3_32_7_, pnd7_.deleted as deleted4_32_7_, pnd7_.pnd_fin as pnd_fin5_32_7_, pnd7_.pnd_intitule as pnd_intitule6_32_7_, pnd7_.modification as modification7_32_7_, pnd7_.obj_code as obj_code10_32_7_, pnd7_.owner as owner8_32_7_, pnd7_.pnd_comment as pnd_comment9_32_7_, objectif8_.obj_code as obj_code1_25_8_, objectif8_.cdmt_code as cdmt_code8_25_8_, objectif8_.obj_comment as obj_comment2_25_8_, objectif8_.creation as creation3_25_8_, objectif8_.deleted as deleted4_25_8_, objectif8_.obj_intitule as obj_intitule5_25_8_, objectif8_.modification as modification6_25_8_, objectif8_.nat_obj_code as nat_obj_code9_25_8_, objectif8_.obj_obj_code as obj_obj_code10_25_8_, objectif8_.owner as owner7_25_8_, objectif8_.prog_code as prog_code11_25_8_, objectif8_.pta_code as pta_code12_25_8_, cdmt9_.cdmt_code as cdmt_code1_4_9_, cdmt9_.cdm_cdmt_code as cdm_cdmt_code7_4_9_, cdmt9_.cdmt_comment as cdmt_comment2_4_9_, cdmt9_.class_cdmt_code as class_cdmt_code8_4_9_, cdmt9_.cdmt_debut as cdmt_debut3_4_9_, cdmt9_.deleted as deleted4_4_9_, cdmt9_.cdmt_fin as cdmt_fin5_4_9_, cdmt9_.cdmt_design as cdmt_design6_4_9_, cdmt9_.prog_code as prog_code9_4_9_, natureobje10_.nat_obj_code as nat_obj_code1_23_10_, natureobje10_.nat_obj_comment as nat_obj_comment2_23_10_, natureobje10_.nat_obj_lib as nat_obj_lib3_23_10_, objectif11_.obj_code as obj_code1_25_11_, objectif11_.cdmt_code as cdmt_code8_25_11_, objectif11_.obj_comment as obj_comment2_25_11_, objectif11_.creation as creation3_25_11_, objectif11_.deleted as deleted4_25_11_, objectif11_.obj_intitule as obj_intitule5_25_11_, objectif11_.modification as modification6_25_11_, objectif11_.nat_obj_code as nat_obj_code9_25_11_, objectif11_.obj_obj_code as obj_obj_code10_25_11_, objectif11_.owner as owner7_25_11_, objectif11_.prog_code as prog_code11_25_11_, objectif11_.pta_code as pta_code12_25_11_, pmo12_.prog_code as prog_code1_31_12_, pmo12_.class_pmo_code as class_pmo_code6_31_12_, pmo12_.prog_debut as prog_debut2_31_12_, pmo12_.prog_fin as prog_fin3_31_12_, pmo12_.prog_design as prog_design4_31_12_, pmo12_.pmo_prog_code as pmo_prog_code7_31_12_, pmo12_.pnd_code as pnd_code8_31_12_, pmo12_.prog_comment as prog_comment5_31_12_, pta13_.pta_code as pta_code1_34_13_, pta13_.cdmt_code as cdmt_code18_34_13_, pta13_.class_pta_code as class_pta_code19_34_13_, pta13_.creation as creation2_34_13_, pta13_.pta_definitif as pta_definitif3_34_13_, pta13_.deleted as deleted4_34_13_, pta13_.pta_desc as pta_desc5_34_13_, pta13_.exer_code as exer_code20_34_13_, pta13_.pta_intitule as pta_intitule6_34_13_, pta13_.modification as modification7_34_13_, pta13_.owner as owner8_34_13_, pta13_.pta_pta_code as pta_pta_code21_34_13_, pta13_.pta_activite as pta_activite9_34_13_, pta13_.pta_cloture as pta_cloture10_34_13_, pta13_.pta_limite_decaisse as pta_limite_decais11_34_13_, pta13_.pta_num_credit as pta_num_credit12_34_13_, pta13_.pta_signature as pta_signature13_34_13_, pta13_.pta_unite_execution as pta_unite_executi14_34_13_, pta13_.pta_vigueur as pta_vigueur15_34_13_, pta13_.pta_ref as pta_ref16_34_13_, pta13_.pta_resultat_annee as pta_resultat_anne17_34_13_, pta13_.sect_code as sect_code22_34_13_, pta13_.struct_code as struct_code23_34_13_, pta13_.typ_proj_code as typ_proj_code24_34_13_, cdmt14_.cdmt_code as cdmt_code1_4_14_, cdmt14_.cdm_cdmt_code as cdm_cdmt_code7_4_14_, cdmt14_.cdmt_comment as cdmt_comment2_4_14_, cdmt14_.class_cdmt_code as class_cdmt_code8_4_14_, cdmt14_.cdmt_debut as cdmt_debut3_4_14_, cdmt14_.deleted as deleted4_4_14_, cdmt14_.cdmt_fin as cdmt_fin5_4_14_, cdmt14_.cdmt_design as cdmt_design6_4_14_, cdmt14_.prog_code as prog_code9_4_14_, classepta15_.class_pta_code as class_pta_code1_7_15_, classepta15_.class_pta_comment as class_pta_comment2_7_15_, classepta15_.class_pta_lib as class_pta_lib3_7_15_, classepta15_.class_pta_niveau as class_pta_niveau4_7_15_, exer16_.exer_code as exer_code1_15_16_, exer16_.exer_en_cours as exer_en_cours2_15_16_, exer16_.exer_lib as exer_lib3_15_16_, pta17_.pta_code as pta_code1_34_17_, pta17_.cdmt_code as cdmt_code18_34_17_, pta17_.class_pta_code as class_pta_code19_34_17_, pta17_.creation as creation2_34_17_, pta17_.pta_definitif as pta_definitif3_34_17_, pta17_.deleted as deleted4_34_17_, pta17_.pta_desc as pta_desc5_34_17_, pta17_.exer_code as exer_code20_34_17_, pta17_.pta_intitule as pta_intitule6_34_17_, pta17_.modification as modification7_34_17_, pta17_.owner as owner8_34_17_, pta17_.pta_pta_code as pta_pta_code21_34_17_, pta17_.pta_activite as pta_activite9_34_17_, pta17_.pta_cloture as pta_cloture10_34_17_, pta17_.pta_limite_decaisse as pta_limite_decais11_34_17_, pta17_.pta_num_credit as pta_num_credit12_34_17_, pta17_.pta_signature as pta_signature13_34_17_, pta17_.pta_unite_execution as pta_unite_executi14_34_17_, pta17_.pta_vigueur as pta_vigueur15_34_17_, pta17_.pta_ref as pta_ref16_34_17_, pta17_.pta_resultat_annee as pta_resultat_anne17_34_17_, pta17_.sect_code as sect_code22_34_17_, pta17_.struct_code as struct_code23_34_17_, pta17_.typ_proj_code as typ_proj_code24_34_17_, secteur18_.sect_code as sect_code1_48_18_, secteur18_.sect_comm as sect_comm2_48_18_, secteur18_.sect_lib as sect_lib3_48_18_, structure19_.struct_code as struct_code1_50_19_, structure19_.struct_lib as struct_lib2_50_19_, structure19_.niv_struct_code as niv_struct_code15_50_19_, structure19_.str_struct_code as str_struct_code16_50_19_, structure19_.struct_sigle as struct_sigle3_50_19_, structure19_.struct_comment as struct_comment4_50_19_, structure19_.struct_contact as struct_contact5_50_19_, structure19_.struct_interne as struct_interne6_50_19_, structure19_.struct_mission_fonc as struct_mission_fon7_50_19_, structure19_.struct_mission_oper as struct_mission_ope8_50_19_, structure19_.struct_resp_fonc as struct_resp_fonc9_50_19_, structure19_.struct_resp_hiera as struct_resp_hiera10_50_19_, structure19_.struct_resp_oper as struct_resp_oper11_50_19_, structure19_.struct_site as struct_site12_50_19_, structure19_.struct_tache_fonc as struct_tache_fonc13_50_19_, structure19_.struct_tache_oper as struct_tache_oper14_50_19_, niveaustru20_.niv_struct_code as niv_struct_code1_24_20_, niveaustru20_.niv_struct_comment as niv_struct_comment2_24_20_, niveaustru20_.niv_struct_lib as niv_struct_lib3_24_20_, niveaustru20_.niv_struct_ordre as niv_struct_ordre4_24_20_, structure21_.struct_code as struct_code1_50_21_, structure21_.struct_lib as struct_lib2_50_21_, structure21_.niv_struct_code as niv_struct_code15_50_21_, structure21_.str_struct_code as str_struct_code16_50_21_, structure21_.struct_sigle as struct_sigle3_50_21_, structure21_.struct_comment as struct_comment4_50_21_, structure21_.struct_contact as struct_contact5_50_21_, structure21_.struct_interne as struct_interne6_50_21_, structure21_.struct_mission_fonc as struct_mission_fon7_50_21_, structure21_.struct_mission_oper as struct_mission_ope8_50_21_, structure21_.struct_resp_fonc as struct_resp_fonc9_50_21_, structure21_.struct_resp_hiera as struct_resp_hiera10_50_21_, structure21_.struct_resp_oper as struct_resp_oper11_50_21_, structure21_.struct_site as struct_site12_50_21_, structure21_.struct_tache_fonc as struct_tache_fonc13_50_21_, structure21_.struct_tache_oper as struct_tache_oper14_50_21_, typeprojet22_.typ_proj_code as typ_proj_code1_52_22_, typeprojet22_.typ_proj_comment as typ_proj_comment2_52_22_, typeprojet22_.typ_proj_lib as typ_proj_lib3_52_22_ from programme_structure programmes0_ inner join cdmt cdmt1_ on programmes0_.cdmt_code=cdmt1_.cdmt_code left outer join cdmt cdmt2_ on cdmt1_.cdm_cdmt_code=cdmt2_.cdmt_code left outer join classe_cdmt classecdmt3_ on cdmt2_.class_cdmt_code=classecdmt3_.class_cdmt_code left outer join pmo pmo4_ on cdmt2_.prog_code=pmo4_.prog_code left outer join classe_pmo classepmo5_ on pmo4_.class_pmo_code=classepmo5_.class_pmo_code left outer join pmo pmo6_ on pmo4_.pmo_prog_code=pmo6_.prog_code left outer join pnd pnd7_ on pmo6_.pnd_code=pnd7_.pnd_code left outer join objectif objectif8_ on pnd7_.obj_code=objectif8_.obj_code left outer join cdmt cdmt9_ on objectif8_.cdmt_code=cdmt9_.cdmt_code left outer join nature_objectif natureobje10_ on objectif8_.nat_obj_code=natureobje10_.nat_obj_code left outer join objectif objectif11_ on objectif8_.obj_obj_code=objectif11_.obj_code left outer join pmo pmo12_ on objectif11_.prog_code=pmo12_.prog_code left outer join pta pta13_ on objectif11_.pta_code=pta13_.pta_code left outer join cdmt cdmt14_ on pta13_.cdmt_code=cdmt14_.cdmt_code left outer join classe_pta classepta15_ on pta13_.class_pta_code=classepta15_.class_pta_code left outer join exercice exer16_ on pta13_.exer_code=exer16_.exer_code left outer join pta pta17_ on pta13_.pta_pta_code=pta17_.pta_code left outer join secteur secteur18_ on pta17_.sect_code=secteur18_.sect_code left outer join structure structure19_ on pta17_.struct_code=structure19_.struct_code left outer join niveau_structure niveaustru20_ on structure19_.niv_struct_code=niveaustru20_.niv_struct_code left outer join structure structure21_ on structure19_.str_struct_code=structure21_.struct_code left outer join type_projet typeprojet22_ on pta17_.typ_proj_code=typeprojet22_.typ_proj_code where programmes0_.struct_code=?
I had the same problem. I'm using SqlResultSetMapping.
The point of SqlResultSetMapping is to defined custom mapping for NamedNativeQuery.
With SqlResultSetMapping, you can either use :
EntityResult to map the result of a query to an Entity object
ConstructorResult to map the result of a query to "non-entity" object with the contructor
ColumnResult
Example with ConstructorResult
Let's say we have a very complex entity ComplexObject with many relations to other objects.
#Entity
#Table(name = "complex_object")
public class ComplexObject {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_complex_object")
private Integer id;
#Column(name = "label")
private String label;
// More relations...
}
I want a query to retrieve only the id and the label of this entity.
In ComplexObject, I define a new NamedNativeQuery as following.
#NamedNativeQueries({
#NamedNativeQuery(name = "ComplexObject.getIdAndLabel", query = "SELECT co.id_complex_object, co.label FROM complex_object", resultSetMapping = "SimpleObject")
})
The important part of this NamedNativeQuery is the resultSetMapping = "SimpleObject".
Then I can define a SimpleObject that is not a entity and match my query as following :
public class SimpleObject {
private Integer id;
private String label;
/**
* This constructor is very important !
* Its signature has to match the SqlResultSetMapping defined in the entity class.
* Otherwise, an exception will occur.
*/
public SimpleObject(Integer id, String label) {
this.id = id;
this.label = label;
}
// Getters and setters...
}
Then I can define the SqlResultSetMapping in ComplexObject as following :
#SqlResultSetMappings({
#SqlResultSetMapping(name = "SimpleObject", classes = {
#ConstructorResult(targetClass = SimpleObject.class, columns = {
#ColumnResult(name = "id_complex_object", type = Integer.class),
#ColumnResult(name = "label", type = String.class)
})
})
})
It's done.
The NamedNativeQuery will use SimpleObject SqlResultSetMapping to construct a SimpleObject (throught the constructor) so your query returns a SimpleObject instead of ComplexObject.
Try adding attribute fetch=FetchType.LAZY to the #ManyToOne on Structure object of Utilisateur entity class.
Since ManyToOne relations are eagerly loaded. I think it is trying to load Structure entity in a new SELECT statement. And this is causing entities with in Structure to be loaded further.
So adding fetch=FetchType.LAZY on Structure should prevent the initial SELECT query of Structure and thus the subsequent entities mapped in the Structure entity.
UPDATE
In the above statements, the assumption you don't want to populate Structure object as you fetch Utilisateur object. If that is not the case, then you can move the FetchType.LAZY further down the association chain. Say you want to fetch Structure but not its related entities like parent etc, then you can move FetchType.LAZY to those annotation (ManyToOne etc).
Note that with the HQL you are using from Utilisateur where deleted is null or deleted <> 1 with no joins it will by default fire a new SELECT query to fetch those LAZY associations by default. And if you want to fetch with single (or lesser number of) query that with joins you need to update your HQL to use JOIN FETCH queries.
One common issue we usually encounter is a scenario where we don't want to fetch an association, but somewhere in the toString method we navigate the associations start printing them and resulting in the LazyInitializationException.

Workaround for HHH-2772 (hibernate querydsl)

I'm trying to perform a query to find cars by their foo property. The properties are stored in a different table.
I have two classes
#Embeddable
#Table(name = "PROPERTY")
public class Property {
#Column(name = "type", nullable = false)
private String type;
#Column(name = "string_value", nullable = true)
private String stringValue;
...
}
#Entity
#Table(name = "CAR")
public class Car {
#Id
...
private String id;
#ElementCollection(fetch = FetchType.EAGER)
#Fetch(FetchMode.SUBSELECT)
#CollectionTable(name = "PROPERTY", joinColumns = #JoinColumn(name = "car_ID") )
private Set<Property> properties = new HashSet<Property>();
...
}
I'm trying to perform a query
QueryDsl:
.from(car)
.leftJoin(car.properties, foo)
.on(foo.type.eq("foo"))
.where(predicate)
Resulting HQL:
select
car
from
com....Car car
left join
car.properties as foo with foo.type = :a1
where
...
This doesn't work because of: https://hibernate.atlassian.net/browse/HHH-2772
Before that, it was possible to write HQL:
SELECT cat FROM Cat cat LEFT JOIN cat.kittens as kitten WITH kitten.owner=:owner
Now the HQL is raising an exception:
org.hibernate.hql.ast.InvalidWithClauseException: with clause can only reference columns in the driving table
Workaround is to explicitly use primary key (ownerId):
SELECT cat FROM Cat cat LEFT JOIN cat.kittens as kitten WITH kitten.owner.ownerId=:ownerId
The problem is that I don't have the ownerId, or an owner, since it's an element collection.
If I were to turn the element collection into a #oneToMany #manyToOne, the property could not longer be embeddable and would require an id. This is not an option. (I can't define a composite ID (this is a requirement), and I don't want to add a new column )
What do you recommend?
Is it possible to add the Car or Car Id as a field into an embaddable class?
Can I create the criteria in a different way?
I'm interested in any workaround that doesn't require database changes. (Hibernate changes or ok)
Thank you

hibernate createAlias with clause generates wrong query

I have the following tables:
A: id
B: id, text
AB: aID, bID
I want to joib A and B where B.text contains the word 'cat'.
This is the hibernate query I do:
Criteria c = session.createCriteria(TableA.class, "A");
c.createAlias("A.bs", "B", JoinType.INNER_JOIN, Restrictions.like("b.text", "%cat%"));
c.setProjection(Projections.property("id"));
The generated query is:
Select id
FROM A a
INNER JOIN AB ab ON a.id=ab.aID AND (b.text like ?)
INNER JOIN B b ON b.id=ab.bID AND (b.text like ?)
For some reason AND (b.text like ?) appears in both inner joins. I far as I understand its supposed to be only in the second on.
This causes the following exception:
java.sql.SQLException: No value specified for parameter 2
I guess it's happening because it has only one parameters and two '?'.
What am I missing?
EDIT:
Adding the persistent classes:
#Entity
#Table(name="A")
Class A {
#Id
#Column(name="id", length=255)
protected String id;
#OneToMany
#JoinTable(name="AB", joinColumns = #JoinColumn( name="aID"), inverseJoinColumns = #JoinColumn( name="bID"))
#LazyCollection(LazyCollectionOption.FALSE)
protected List<B> bs;
}
#Entity
#Table(name="B")
Class B {
#Id
#Column(name="id", length=255)
protected String id;
#Column(name="text", length=255)
protected String text;
}
I think you need to create an alias
c.createAlias("A.bs", "b", JoinType.INNER_JOIN, Restrictions.like("b.text", "%cat%"));
Updated
I think It is a Hibernate bug. You can fix it by using a restriction in the where clause
c.createAlias("A.bs", "b", JoinType.INNER_JOIN);
c.add(Restrictions.like("b.text", "%cat%"));
or don't use join table and do association by foreign key in B.

Categories

Resources