Ebean inner Join on self table - java

Is there a way to get partial object tree on child objects with parent child structure so I can achive:
select distinct * from kb_event t0 inner join kb_event t1 on t1.parent_id = t0.id where t1.status = -1;
My eban query
Ebean.getServer("default").find(EventModel.class)
.select("children.id, name, status").fetch("children")
.where()
.eq("children.status", -1)
.findList();
Returns parent element but with all children listed under children node.
My model looks like:
#Entity
#Table(name = "kb_event")
public class EventModel extends Model implements Bean {
#Id
#JsonProperty("eventId")
Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")
public List<EventModel> children;
#ManyToOne
public EventModel parent;
}
with proper foreign key on parent Id

Related

Hibernate deletes one child enitity too much, after exiting Transactional context

I've encountered a strange problem in a simple Spring Boot application, where I update a parent entity, delete all of its children and then create new ones.
After saving, the resulting entity looks fine and has all of the new children, but when I query it again, I find that one of the child entities is lost!
The quick and dirty solution for this would be to split the code into two transactions, but I want to understand the cause the orphan removal to act like this.
Here's the service code:
#Service
public class ParentService {
private final EntityManager em;
public ParentEntity getParent(UUID parentId) {
return em.createQuery(
"SELECT p " +
"from ParentEntity p " +
"JOIN FETCH p.children " +
"WHERE p.id = :parentId", ParentEntity.class)
.setParameter("parentId", parentId)
.getSingleResult();
}
#Transactional
public ParentEntity resetChildren(UUID parentId) {
var parent = getParent(parentId);
parent.getChildren().clear();
addChildren(parent, 2);
em.persist(parent);
return parent;
}
private void addChildren(ParentEntity parent, int childCount) {
for (var i = 0; i < childCount; i++) {
parent.addChildren(new ChildEntity());
}
}
}
The SQL output after resetting children and the fetching the parent again is this:
select parententi0_.id as id1_1_0_, children1_.parent_id as parent_i2_0_1_, children1_.id as id1_0_1_, children1_.id as id1_0_2_, children1_.parent_id as parent_i2_0_2_ from parent parententi0_ left outer join child children1_ on parententi0_.id=children1_.parent_id where parententi0_.id=?
insert into child (parent_id, id) values (?, ?)
insert into child (parent_id, id) values (?, ?)
delete from child where id=?
delete from child where id=?
delete from child where id=? <-- One extra delete
select parententi0_.id as id1_1_0_, children1_.parent_id as parent_i2_0_1_, children1_.id as id1_0_1_, children1_.id as id1_0_2_, children1_.parent_id as parent_i2_0_2_ from parent parententi0_ left outer join child children1_ on parententi0_.id=children1_.parent_id where parententi0_.id=?
The entities look like this:
The parent
#Entity
#Table(name = "parent")
public class ParentEntity {
#Id
#GeneratedValue
private UUID id;
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<ChildEntity> children = new HashSet<>();
...
public void addChildren(ChildEntity child) {
this.children.add(child);
child.setParent(this);
}
...
}
And the child
#Entity
#Table(name = "child")
public class ChildEntity {
#Id
#GeneratedValue
private UUID id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "parent_id")
private ParentEntity parent;
...
}
An important note to this, that in my use case, the id of these entities is a UUID. I can't get it working with any numeric ids
The code repository with a unit test can be found here
An interesting thing happens, if I decide to add 1 child, instead of two or more, the parent itself is deleted! Because of this, it feels like I'm looking at a bug in Hibernate.
The problem was that I had cascade on the child side, which lead to very very weird results. I don't want parent to be deleted on cascade, so I don't need that.
The fix was to change the child to this:
#Entity
#Table(name = "child")
public class ChildEntity {
#Id
#GeneratedValue
private UUID id;
#ManyToOne // <---- No more cascade!
#JoinColumn(name = "parent_id")
private ParentEntity parent;
...
}

How to fetch parent and all its children with criteria using Spring Data Jpa?

I have a Parent and Child entities like below -
class Parent {
Long id;
List<Child> children;
}
class Child {
Long id;
String status; // ACTIVE or INACTIVE
Parent parent;
}
I would like to fetch the parent along with all its children having status=ACTIVE property.
public interface ParentRepository<Parent, Long> {
Parent findByIdAndChildStatus(#Param("id") id, #Param("childStatus") status);
}
Question is -
What is the easiest way to fetch only ACTIVE children?
Is it possible to set ACTIVE query condition on the Child entity's
status property to fetch only active child entities by default?
Will something like above query method work?
See below
It's not possible with Spring annotations alone, but you can achieve it with Hibernate's #Where:
#Entity
#Getter
#Setter
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Where(clause = "status='ACTIVE'")
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> children;
}
Your query method would not work, Spring Data wouldn't understand the method name. To make it work, the Child entity would need to be in the plural form:
public interface ParentRepository extends CrudRepository<Parent, Long> {
Parent findByIdAndChildrenStatus(Long id, String status);
}
Unfortunately, the meaning of the method would be a bit different than expected. It would mean: get Parent with the id id and having a Child with the status status. The generated query looks as follows:
SELECT parent0_.id AS id1_1_
FROM parent parent0_
LEFT OUTER JOIN child children1_ ON parent0_.id=children1_.parent_id
WHERE parent0_.id=? AND children1_.status=?

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.

Hibernate Inheritance, parent classes should be child or parent based on decider

Trying to achieve inheritance in Hibernate.
Following is schema
Here is What, Classes are,
//Grand Parent Class
#Entity
#Table(name="grand_parent")
public class GrandParent{//consider #id}
//Parent Class
#Entity
#Table(name = "parent")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "decider", discriminatorType = DiscriminatorType.STRING)
public class Parent{//consider #id}
//ChildX class
#Entity
#Table(name = "childX")
#PrimaryKeyJoinColumn(name="id")
#DiscriminatorValue("X")
public class ChildX() extends Parent{//consider value}
//ChildY class
#Entity
#Table(name = "childY")
#PrimaryKeyJoinColumn(name="id")
#DiscriminatorValue("Y")
public class ChildY extends Parent(//consider value){}
//ChildZ class
#Entity
#Table(name = "childZ")
#PrimaryKeyJoinColumn(name="id")
#DiscriminatorValue("Z")
public class ChildZ() extends Parent{//consider value}
Use Case:
If decider is 'K', and 4 records need to be saved then 4 parent records should be added
If decider is 'X/Y/Z', and 4 records need to be saved then, 1 parent record and 4 ChildX/ChildY/ChildZ records should be added.
However, parent table should be treated as single child when decider is 'K' and it must be acted as parent when decider is 'X/Y/Z'
But with above class diagram, Whenever decider is 'X/Y/Z', 4 records saved in ChildX/ChildY/ChildZ and no record in parent table.
Also how to retrieve above records.
EDITS
#Entity
#Table(name="grand_parent")
public class GrandParent{
#OneToMany(mappedBy = "parentRecord",
fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
#Cascade(org.hibernate.annotations.CascadeType.DELETE)
private List<parent> parentList;
}
//Parent Class
#Entity
#Table(name = "parent")
public class Parent{
#ManyToOne()
#JoinColumn(name = "fk_gp_id")
private GrandParent parentRecord;
#OneToMany(mappedBy = "childrecord",
fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
#Cascade(org.hibernate.annotations.CascadeType.DELETE)
private List<Child> childList;
}
#Entity
#DiscriminatorColumn(name = "decider", discriminatorType = DiscriminatorType.STRING)
public abstract class Child(){
#ManyToOne(optional = false)
#JoinColumn(name = "fk_parent_id")
private parent childrecord;
}
//ChildX class
#Entity
#Table(name = "childX")
#DiscriminatorValue("X")
public class ChildX() extends Parent{//consider value}
......
To add..
GrandParent gp = new GrandParent();
Parent p = new Parent();
ChildX ch = new ChildX();
ch.setChildrecord(p);
p.setChildList(//Array added ch);
p.setParentRecord(gp);
gp.setParentList(//Array added p);
persist(gp);
Now I am getting an error:
Application error : com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'Child' doesn't exist
When you use (Joined) inheritance you will always insert a row in both the Parent and Child table when you persist a child. This means that every Parent has at most one child.
In you table diagram, you have multiple children with the same parent, this is not inheritance, this is a OneToMany Entity relationship, which is confirmed by your ER diagram.
My guess is that you are looking for something like this:
#Entity
public class Parent {
#Id
private long id;
#OneToMany(mappedBy = "parent")
private Collection<Child> children;
}
#Entity
#DiscriminatorColumn(name = "decider", discriminatorType = DiscriminatorType.STRING)
public abstract class Child {
#Id
private long id;
#ManyToOne
private Parent parent;
// other common fields
}
#Entity
#DiscriminatorValue("X")
public class ChildX extends Child {
// specific fields for child x
}
// more children types
A parent can have many children, and these children can be of different types. The child base class has the foreign key column referencing the parent, in my experience inheritance base classes often end up being abstract.
EDIT: Here is an example of code that stores a Parent and a specific child.
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
Parent p = new Parent();
ChildX childX = new ChildX();
childX.setParent(p);
em.persist(p);
em.persist(childX);
em.getTransaction().commit();
} finally {
em.close();
}

Hibernate HQL Query to get parent + children based on childID

I have an object with several #onetomany relationships, and I need to query for properties in the parent, as well as properties of the children. I can't seem to get it done.
For example, I need a query that lets me see the Parent objects where where the parent's name is "John" and the child's favorite color is blue. Hope that makes sense. The reason for the complication seems to be that children are in a list, not in a #onetoone relationship.
PARENT:
#Entity
#Table(name="Parent")
public class Parent {
#Id
#Column(name="ID")
#GeneratedValue(strategy=GenerationType.AUTO, generator="parent_gen")
#SequenceGenerator(name="parent_gen", sequenceName="PARENT_SEQUENCE")
private int parentID;
#Column(name="name")
private String name;
#OneToMany(cascade=CascadeType.ALL)
#OrderBy("name ASC")
#JoinTable(name = "parent_to_child")
private List<Child> childList;
// and so forth
Child
#Entity
#Table(name="Child")
public class Child{
#Id
#Column(name="ID")
#GeneratedValue(strategy=GenerationType.AUTO, generator="child_gen")
#SequenceGenerator(name="child_gen", sequenceName="CHILD_SEQUENCE")
private int childID;
#Column(name="favoriteColor")
private String favoriteColor;
// and so forth
select p from Parent p join p.childList c
where p.name = 'John' and c.favoriteColor = 'blue'
This will return a List<Parent>.
You can look all this in the hql reference
Try something as follows:
from Parent as parent
left join parent.childList as children
with children.favoriteColor = 'blue'
where parent.name = 'John'
you need to do--- parent "left join fetch" child with your condition.
"left join fetch" gives result in List< Parent>
Without Fetch it will be List where object[0] = parent and object[1] = child.
public class Clients implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany(cascade = { CascadeType.ALL},orphanRemoval=true)
#JoinColumn(name="client_id")
List<SmsNumbers> smsNumbers;
}
#Table(name="smsnumbers")
public class SmsNumbers implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
String number; //getter and setter
}
On the basis of child class i fetch the parent in unidirectional relation using the following criteria-
Session session = HibernateUtil.openSession();
try{
Criteria criteria=session.createCriteria(Clients.class);
criteria.createAlias("smsNumbers", "child");
criteria.add(Restrictions.eq("child.number", phone).ignoreCase());
Clients cli=(Clients) criteria.list().get(0);
System.out.println(cli.getId());
}catch (Exception e) {
// TODO: handle exception
}
JPQL provides a special syntax that, in these cases, makes things easier and helps you to think in an Oriented Object way:
SELECT p FROM Parent P, IN (P.childList) C
WHERE P.name='John' and C.favoriteColor='blue';
The operator IN iterates over lists, thus avoiding the need of using JOINs.
Criteria criteria=session.createCriteria(Parent.class);
criteria.add(Restrictions.eq("name", "John"));
criteria.createAlias("childList", "child");
criteria.add(Restrictions.eq("child.favoriteColor", "Blue").ignoreCase());
You can try with criteria API also.

Categories

Resources