On a fait un appli, utilisant Struts1.2 et Hibernate 3.
Il y a une page, par laquelle on insère un Customer objet, et après tant de difficultés confrontées pour se débrouiller avec les différents Customer properties. Je viens d'être coincées en se débrouillant avec le property nommé Partner dont le Customer peut avoir plusieurs.
Voilà les mapping files de Customer, Partner:
Customer.hbm.xml:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
    <class name="com.primasoft.housing.model.Customer" table="CUSTOMER" schema="HOUSE">
        <id name="customerId" type="long">
            <column name="CUSTOMER_ID" precision="22" scale="0" />
            <generator class="increment" />
        </id>
        <property name="customerName" type="string">
            <column name="CUSTOMER_NAME" length="300" />
        </property>
        <many-to-one name="customer" class="com.primasoft.housing.model.Customer" fetch="select">
            <column name="PARENT_CUSTOMER_ID" precision="22" scale="0" />
        </many-to-one>
        <set name="realEstateAssignTranses" inverse="true">
            <key>
                <column name="CUSTOMER_ID" precision="22" scale="0" />
            </key>
            <one-to-many class="com.primasoft.housing.model.RealEstateAssignTrans" />
        </set>
        <set name="wifes" inverse="true" >
            <key>
                <column name="CUSTOMER_ID" precision="22" scale="0" />
            </key>
            <one-to-many class="com.primasoft.housing.model.Wife" />
        </set>
        <set name="childs" inverse="true" >
            <key>
                <column name="CUSTOMER_ID" precision="22" scale="0" />
            </key>
            <one-to-many class="com.primasoft.housing.model.Child" />
        </set>
        <set name="customers" inverse="true">
            <key>
                <column name="PARENT_CUSTOMER_ID" precision="22" scale="0" />
            </key>
            <one-to-many class="com.primasoft.housing.model.Customer" />
        </set>
        <set name="partners" inverse="true" >
            <key>
                <column name="CUSTOMER_ID" precision="22" scale="0" />
            </key>
            <one-to-many class="com.primasoft.housing.model.Partner" />
        </set>
    </class>
</hibernate-mapping>
Partner.hbm.xml:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
    <class name="com.primasoft.housing.model.Partner" table="PARTNER" schema="HOUSE">
        <id name="partnerId" type="long">
            <column name="PARTNER_ID" precision="22" scale="0" />
            <generator class="increment" />
        </id>
        <many-to-one name="partnerLegalType" class="com.primasoft.housing.model.PartnerLegalType" fetch="select">
            <column name="PARTNER_LEGAL_TYPE_ID" precision="22" scale="0" />
        </many-to-one>
        <many-to-one name="customer" class="com.primasoft.housing.model.Customer" fetch="select">
            <column name="CUSTOMER_ID" precision="22" scale="0" />
        </many-to-one>
        <many-to-one name="country" class="com.primasoft.housing.model.Country" fetch="select">
            <column name="COUNTRY_ID" precision="22" scale="0" />
        </many-to-one>
        <property name="partnerName" type="string">
            <column name="PARTNER_NAME" length="300" />
        </property>
        <property name="partnerShare" type="string">
            <column name="PARTNER_SHARE" length="200" />
        </property>
    </class>
</hibernate-mapping>
Ce Partner class a 2 classes; Country et PartnerLegalType qui référencent une One-to-Many relation. Ça veut dire que Country et PartnerLegalType sont des look up tables.
PartnerLegalType.hbm.xml:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
    <class name="com.primasoft.housing.model.PartnerLegalType" table="PARTNER_LEGAL_TYPE" schema="HOUSE">
        <id name="partnerLegalTypeId" type="long" >
            <column name="PARTNER_LEGAL_TYPE_ID" precision="22" scale="0" />
            <generator class="native"/>
        </id>
        <property name="partnerLegalTypeName" type="string">
            <column name="PARTNER_LEGAL_TYPE_NAME" length="100" />
        </property>
        <set name="partners" inverse="true">
            <key>
                <column name="PARTNER_LEGAL_TYPE_ID" precision="22" scale="0" />
            </key>
            <one-to-many class="com.primasoft.housing.model.Partner" />
        </set>
    </class>
</hibernate-mapping>
Country.hbm.xml:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
    <class name="com.primasoft.housing.model.Country" table="COUNTRY" schema="HOUSE">
        <id name="countryId" type="long">
            <column name="COUNTRY_ID" precision="22" scale="0" />
            <generator class="native"/>
        </id>
        <property name="countryName" type="string">
            <column name="COUNTRY_NAME" length="50" />
        </property>
        <set name="customers" inverse="true">
            <key>
                <column name="COUNTRY_ID" precision="22" scale="0" />
            </key>
            <one-to-many class="com.primasoft.housing.model.Customer" />
        </set>
        <set name="partners" inverse="true">
            <key>
                <column name="COUNTRY_ID" precision="22" scale="0" />
            </key>
            <one-to-many class="com.primasoft.housing.model.Partner" />
        </set>
    </class>
</hibernate-mapping>
Le scénario n'oblige pas l'utilisateur en insérant ce nouveau Partner de choisir son Country ou PartnerLegalType, qui sont exposés dans des combo box.
D'ici, quand j'insère un nouveau Customer, et par la conséquence un nouveau Partner, une org.hibernate.TransientObjectException est confrontée quand le Partner insertion commit est exécuté:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//Partners
      TreeMap partnersCopy=customerInfoForm.getPartnersCopy();
      Set partnersSet=partnersCopy.keySet();
      Iterator partnersSetIterator=partnersSet.iterator();
      while (partnersSetIterator.hasNext())
      {
        Partner partner = (Partner)partnersCopy.get((String)partnersSetIterator.next());
        //Checkin if the end user submitted the map with only 1 row contaning nothing, cos such case will add empty data in the database
        //Only customers with category 2شركات can have partners, so we check customer category also
        if ((partnersCopy.size()>1||(partnersCopy.size()==1&&!partner.getPartnerName().equals("")))&&custCat.equals(new Long("2")))
        {
          //Setting the master customer id before saving the partner object.
          partner.getCustomer().setCustomerId(customer.getCustomerId());
          //In case the same customer is inserted once again with a different code, we have to allow partners to be inserted also
          partner.setPartnerId(null);
          //Setting -100 values with null
          if (partner.getCountry().getCountryId().equals(new Long("-100")))
          {
            partner.getCountry().setCountryId(null);
          }
          if (partner.getPartnerLegalType().getPartnerLegalTypeId().equals(new Long("-100"))) 
          {
            partner.getPartnerLegalType().setPartnerLegalTypeId(null);
          }
          Transaction transaction2 = saveOrUpdateSession.beginTransaction();
          saveOrUpdateSession.saveOrUpdate(partner);
          transaction2.commit();
        }
      }
Je sais que l'utilisateur n'a pas choisi la valeur du Country ou du PartnerLegalType si leurs ID=-100.
et voici l'exception:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
org.hibernate.TransientObjectException: com.primasoft.housing.model.PartnerLegalType
 
	at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:216)
 
	at org.hibernate.type.EntityType.getIdentifier(EntityType.java:108)
 
	at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:221)
 
	at org.hibernate.type.TypeFactory.findDirty(TypeFactory.java:476)
 
	at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:2803)
 
	at org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:467)
 
	at org.hibernate.event.def.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:190)
 
	at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:113)
 
	at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:195)
 
	at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
 
	at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
 
	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1009)
 
	at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:356)
 
	at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
 
	at com.primasoft.housing.transactions.CustomerInfoTransaction.insertOrUpdateCustomer(CustomerInfoTransaction.java:528)
 
	at com.primasoft.housing.action.CustomerInfoAction.execute(CustomerInfoAction.java:70)
 
	at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:419)
 
	at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:224)
 
	at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1192)
 
	at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
 
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
 
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
 
	at com.evermind.server.http.ResourceFilterChain.doFilter(ResourceFilterChain.java:65)
 
	at oracle.security.jazn.oc4j.JAZNFilter.doFilter(Unknown Source)
 
	at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:663)
 
	at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:330)
 
	at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:830)
 
	at com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:285)
 
	at com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:126)
 
	at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:192)
 
	at java.lang.Thread.run(Thread.java:534)