Je suis persuadé qu'il y a un probleme de conception (moi qui voulais laisser hibernate etre intelligent a ma place)...
mais il ya autre chose qui me gène dans cette histoire.
je reprends depuis le début :
--------------------- premiere approche ---------------------------
la base :
Code:
drop table ref;
create table REF (
DISC varchar(255) not null,
CODE varchar(255),
LIBELLE varchar(255),
primary key (DISC,CODE)
)
insert into REF values('COULEUR','1','bleu');
insert into REF values('COULEUR','2','rouge');
insert into REF values('MARQUE','1','HONDA');
insert into REF values('MARQUE','2','PIGEOT');
drop table VOITURE;
create table VOITURE (
ID varchar(255) not null,
COULEUR_CODE varchar(255),
MARQUE_CODE varchar(255),
primary key (ID)
)
insert into VOITURE values( '1','2','2');
insert into VOITURE values( '2','1','1');
le HBM:
Code:
<class abstract="true" name="Reference" table="REF" polymorphism="explicit" discriminator-value="null">
<id name="code" column="CODE" type="string" />
<discriminator column="DISC" type="string" />
<property name="libelle" column="LIBELLE" type="string"/>
<subclass name="Couleur" discriminator-value="COULEUR" />
<subclass name="Marque" discriminator-value="MARQUE" />
</class>
<class name="Voiture" table="VOITURE">
<id name="id" column="ID" type="string"/>
<many-to-one name="couleur" column="COULEUR_CODE" class="Couleur"/>
<many-to-one name="marque" column="MARQUE_CODE" class="Marque" />
</class>
evidement les contraintes SGBD ne sont pas respectées, mais peu importe, ceci me parait logique...
le problème:
Code:
System.out.println("1>>les couleurs :"+sf.getCurrentSession().createCriteria(Couleur.class).list());
System.out.println("2>>les marques :"+sf.getCurrentSession().createCriteria(Marque.class).list());
donne
Code:
org.hibernate.WrongClassException: Object with id: 1 was not of the specified subclass: Marque (loaded object was of wrong class)
at org.hibernate.loader.Loader.instanceAlreadyLoaded(Loader.java:1235)
at org.hibernate.loader.Loader.getRow(Loader.java:1186)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:568)
at org.hibernate.loader.Loader.doQuery(Loader.java:689)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:223)
at org.hibernate.loader.Loader.doList(Loader.java:2147)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2026)
at org.hibernate.loader.Loader.list(Loader.java:2021)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:94)
si CODE de la table reference est unique, tout est ok.
Mais CODE est seulement unique pour un discriminant donné (composite).
Je m'etais imaginé que hibernate prennait en compte ceci...que le discriminant permettait de travailler
avec un sous ensemble d'une table de maniere transparente.
--------------------- une solution avec pk composite ---------------------------
la base :
Code:
drop table ref;
create table REF (
DISC varchar(255) not null,
CODE varchar(255),
LIBELLE varchar(255),
primary key (DISC,CODE)
)
insert into REF values('COULEUR','1','bleu');
insert into REF values('COULEUR','2','rouge');
insert into REF values('MARQUE','1','HONDA');
insert into REF values('MARQUE','2','PIGEOT');
drop table VOITURE;
create table VOITURE (
ID varchar(255) not null,
COULEUR_DISC varchar(255),
COULEUR_CODE varchar(255),
MARQUE_DISC varchar(255),
MARQUE_CODE varchar(255),
primary key (ID)
)
insert into VOITURE values( '1','COULEUR','2','MARQUE','2');
insert into VOITURE values( '2','COULEUR','1','MARQUE','1');
le HBM:
Code:
<class name="Reference" table="REF" polymorphism="explicit" discriminator-value="null">
<composite-id>
<key-property name="disc" column="DISC" type="string" />
<key-property name="code" column="CODE" type="string" />
</composite-id>
<discriminator column="DISC" type="string" insert="false" />
<property name="libelle" column="LIBELLE" type="string"/>
<subclass name="Couleur" discriminator-value="COULEUR" />
<subclass name="Marque" discriminator-value="MARQUE" />
</class>
<class name="Voiture" table="VOITURE">
<id name="id" column="ID" type="string"/>
<many-to-one name="couleur" class="Couleur" >
<column name="COULEUR_DISC" ></column>
<column name="COULEUR_CODE" ></column>
</many-to-one>
<many-to-one name="marque" class="Marque" >
<column name="MARQUE_DISC" ></column>
<column name="MARQUE_CODE" ></column>
</many-to-one>
</class>
le problème:
ceci est ok
Code:
System.out.println("1>>les couleurs :"+sf.getCurrentSession().createCriteria(Couleur.class).list());
System.out.println("2>>les marques :"+sf.getCurrentSession().createCriteria(Marque.class).list());
System.out.println(">>la voiture 1 :"+sf.getCurrentSession().get(Voiture.class,"1"));
mais session.get() et session.load() sont inutilisables sans créer une classe interne id(disc, code), deplus il est
hors de question de gerer les discriminant a ce niveau...
il reste quand meme la solution :
Code:
System.out.println(">>la marque 1 :"+sf.getCurrentSession().createCriteria(Marque.class).add(Restrictions.eq("code","1")).list());
System.out.println(">>la couleur 1 :"+sf.getCurrentSession().createCriteria(Couleur.class).add(Restrictions.eq("code","1")).list());
la création d'une colonne suplementaire pour chaque association me parait ici superflu, car le type est connu...
--------------------- solution sans heritage ---------------------------
la base :
Code:
drop table ref;
create table REF (
DISC varchar(255) not null,
CODE varchar(255),
LIBELLE varchar(255),
primary key (DISC,CODE)
)
insert into REF values('COULEUR','1','bleu');
insert into REF values('COULEUR','2','rouge');
insert into REF values('MARQUE','1','HONDA');
insert into REF values('MARQUE','2','PIGEOT');
insert into REF values('OPTION','1','CLIM');
insert into REF values('OPTION','2','ABS');
insert into REF values('OPTION','3','VOLANTMOUMOUT');
drop table VOITURE;
create table VOITURE (
ID varchar(255) not null,
COULEUR_CODE varchar(255),
MARQUE_CODE varchar(255),
primary key (ID)
)
insert into VOITURE values( '1', '2', '2');
insert into VOITURE values( '2', '1', '1');
drop table VOITURE_OPTIONS;
create table VOITURE_OPTIONS (
VOITURE_ID varchar(255),
OPTION_CODE varchar(255),
primary key (VOITURE_ID, OPTION_CODE)
)
insert into VOITURE_OPTIONS values( '1', '1');
insert into VOITURE_OPTIONS values( '1', '2');
insert into VOITURE_OPTIONS values( '2', '3');
insert into VOITURE_OPTIONS values( '2', '2');
le HBM:
Code:
<class name="Couleur" table="REF" where="DISC='COULEUR'" >
<id name="code" column="CODE" type="string" />
<property name="libelle" column="LIBELLE" type="string"/>
</class>
<class name="Marque" table="REF" where="DISC='MARQUE'" >
<id name="code" column="CODE" type="string" />
<property name="libelle" column="LIBELLE" type="string"/>
</class>
<class name="Option" table="REF" where="DISC='OPTION'" >
<id name="code" column="CODE" type="string" />
<property name="libelle" column="LIBELLE" type="string"/>
</class>
<class name="Voiture" table="VOITURE">
<id name="id" column="ID" type="string"/>
<many-to-one name="couleur" class="Couleur" column="COULEUR_CODE" />
<many-to-one name="marque" class="Marque" column="MARQUE_CODE" />
<set name="options" table="VOITURE_OPTIONS" >
<key column="VOITURE_ID"/>
<many-to-many unique="true" class="Option" column="OPTION_CODE" where="DISC='OPTION'"/>
</set>
</class>
pas de problème:
les classes heritent de reference et tout me parait ok avec cette solution.
Il y a t-il une contre indication avec cette approche?
des conseils ?
merci, David