Beispiel: Container Managed Relationship mit Container-Generated Primary Keys
(JBoss 4.0)
Beispiel für zwei Container Managed Entity Bean, auf die per Webclient zugegriffen wird.
Zwischen den beiden Beans besteht eine Container Managed Relationship, der Primary Key ist Container-erzeugt.
Die Deployanleitung bezieht sich auf JBoss 4.0.3.
Hier gibt es das Projekt zum Download (dies ist ein EAR-Export, die Importanleitung findet
man im Stateless-Beispiel): KuchenZutatAutoPK.ear
ACHTUNG: Nach dem Import XDoclet-Builder im EJB-Projekt aktivieren ! (Das Web-Projekt
verfügt über keine Servlets, deshalb kann WebDoclet dort nicht verwendet werden)
Aufbau des Beispieles
a) Entity Bean-Klasse für Kuchen mit Local-Interfaces.
b) Entity Bean-Klasse für Zutat mit Local-Interfaces.
c) Webclient
Inhalt:
Anlegen der Application
Anlegen der Entity Bean "KuchenAutoPK"
Anlegen der Entity-Bean "ZutatAutoPK"
Anlegen des Webclients
Anlegen der Application
Ein "EAR Application Project" mit dem Namen "KuchenZutatAutoPK" erstellen.
Zu erzeugende Module definieren. Dieses Beispiel benötigt ein EJB-Projekt und
ein Anwendungsclientprojekt.
Im Project Explorer sollte es so aussehen (die angezeigte Fehlermeldung kommt daher dass
der Deploymentdeskriptor "ejb-jar.xml" gerade keine Bean-Einträge enthält und deshalb ungültig ist):
Anlegen der Entity Bean "KuchenAutoPK"
Wir legen eine Session Bean namens "KuchenAutoPKBean" im Projekt "com.knauf.ejb.kuchenzutatautopk" an.
Im letzten Schritt ändern wir das zu implementierende Interface von "javax.ejb.SessionBean"
auf "javax.ejb.EntityBean".
Den Rest der Arbeit müssen wir in der Bean-Klasse und mittels XDoclet erledigen.
-
Zuerst einmal ändern wir die XDoclet-Definition im Klassenkopf:
* @ejb.bean name="KuchenAutoPK"
* description="Ein Kuchen, mit Container-erzeugtem Primary Key"
* display-name="KuchenAutoPK"
* jndi-name="KuchenAutoPK"
* type="CMP"
* transaction-type="Container"
* cmp-version="2.x"
* view-type="local"
* @ejb.pk
* class="java.lang.Object"
* generate="false"
* @jboss.unknown-pk
* class="java.lang.Integer"
* column-name="kuchenid"
* field-name="kuchenid"
* sql-type="INTEGER"
* jdbc-type="INTEGER"
* auto-increment="true"
* @jboss.entity-command
* name="hsqldb-fetch-key"
Wir möchten eine CMP-Entity-Bean haben. Der Primary Key soll vom Container generiert werden und vom Typ
java.lang.Object
sein.
Wir geben außerdem die JBoss-spezifischen Angaben für das Erzeugen des Primary Keys an.
-
Die Dummy-Methode "foo" wird entfernt.
-
Jetzt wird das einzige Feld der Klasse zugefügt: Name (vom Typ java.lang.String).
/**Abrufen des Kuchen-Namens.
* @return der Kuchen-Name.
*
* @ejb.persistence column-name="name" sql-type="VARCHAR"
* @ejb.interface-method view-type="local"
*/
public abstract String getName();
/**Setzen des Kuchen-Namens.
* @param str_Name der Name
*
* @ejb.persistence column-name="name" sql-type="VARCHAR"
* @ejb.interface-method view-type="local"
*/
public abstract void setName (String str_Name);
- Die beiden ejbCreate-Methoden werden erzeugt, die jeweils NULL zurückgeben und den Rückgabetyp
java.lang.Object
haben.
"ejbCreate" mit dem Kuchennamen als Parameter sieht so aus (für ejbCreate ohne Parameter analog):
/**Erzeugen eines Kuchen-Objekts, wobei der Name angegeben wird.
* Es wird kein Key erzeugt (macht der Container)
* @param str_Name Der Name des Kuchens.
* @return NULL da die ID vom Container kommt.
* @exception CreateException Fehler beim Erzeugen.
*
* @ejb.create-method view-type="local"
*/
public Object ejbCreateByName (String str_Name) throws CreateException
{
KuchenAutoPKBean.logger.info("ejbCreateByName: " + str_Name);
this.setName(str_Name);
return null;
}
Natürlich müssen die zugehörigen ejbPostCreate-Methoden ebenfalls deklariert werden.
- Die Deklaration der Finder-Methode wird im Klassen-Kopf zugefügt:
* @ejb.finder
* signature="java.util.Collection findAll()"
* query="select Object(o) from KuchenAutoPK o order by o.name"
Anlegen der Entity-Bean "ZutatAutoPK"
Diese Bean kopieren wir am besten aus "KuchenAutoPKBean" und ersetzen überall "KuchenAutoPK" durch "ZutatAutoPK"
(auch in EJB-QL !). Wenn wir das Kopieren innerhalb des Project Explorer durchführen ("KuchenAutoPKBean"
wählen -> Copy -> Paste im Package com.knauf.ejb.kuchenzutatautopk
, dann fordert Eclipse
uns zur Eingabe eines neuen Namens auf und ersetzt auch den Klassennamen im Code. Anschließend die Finder-Methode
findAll
entfernen, die brauchen wir in der Zutat nicht.
Die Property "name" in "zutatName" ändern.
Es wird ein Feld "Menge" vom Typ java.lang.String
zugefügt.
Die Methode "ejbCreateByName" wird ersetzt durch "ejbCreateByNameMenge".
Hinzufügen der Relationships
In "KuchenBean" fügen wir die folgenden beiden Methoden zu:
/**Abrufen aller Zutaten dieses Kuchens.
* @return Collection von Zutat-Objekten.
* @ejb.interface-method view-type="local"
* @ejb.relation
* name="KuchenZutaten"
* role-name="kuchen-hat-zutaten"
*/
public abstract Collection getZutaten();
/**Setzen der kompletten Zutaten-Liste des Kuchens.
* Wird vom Container übernommen.
* @param coll_Zutaten Liste der Zutaten.
*
* @ejb.interface-method view-type="local"
*/
public abstract void setZutaten (Collection coll_Zutaten);
Außerdem werden die beiden Hilfsmethoden "addZutat" und "getZutatenListe" zugefügt, beide
sollen in das Local-Interface eingebaut werden.
In der Zutat-Bean wird getKuchen und setKuchen eingebaut. Hier wird die andere Seite der Relation
deklariert:
/**Abrufen des Kuchens, zu dem die Zutat gehört.
* @return Der Kuchen der Zutat.
*
* @ejb.interface-method view-type="local"
* @ejb.relation
* name="KuchenZutaten"
* role-name="zutat-hat-kuchen"
* cascade-delete="yes"
* @jboss.relation fk-constraint="true"
* related-pk-field="kuchenid"
* fk-column="kuchen_fk"
*/
public abstract KuchenAutoPKLocal getKuchen();
/**Setzen des Kuchens, zu dem die Zutat gehört.
* @param kuchen Der Kuchen der Zutat.
*
* @ejb.interface-method view-type="local"
*/
public abstract void setKuchen(KuchenAutoPKLocal kuchen);
Hierzu wichtig:
-Der Name der Relation (hier: "KuchenZutaten") muss auf beiden Seiten der Relation gleich sein.
-Die Deklaration ist so zu lesen: bei der Methode der ZutatBean wird deklariert wie die Relation zur ZutatBean aus
Sicht des Kuchens sich verhalten soll (es gibt viele Zutaten (Many), beim Löschen des Kuchens soll die Zutat
gelöscht werden).
-Auf der Zutat-Seite muss eine @jboss-relation
deklariert werden, da der Server sonst eine Fehlermeldung
ausspuckt. Mittels dieser JBoss-Relation geben wir an auf welches Primary-Key-Feld der KuchenBean sich
die Relation "KuchenZutat" bezieht (wichtig: der Name dieses Felds ist im @jboss.unknown-pk
-Tag deklariert)
und wie das Feld in der Tabelle "Zutat" heißen soll. Auf der
Gegenseite (im Kuchen) ist eine solche Angabe nicht erlaubt, da die KuchenBean kein
Forein-Key-Feld auf die ZutatBean hat.
In "ejb-jar.xml" sieht das dann so aus:
<relationships >
<ejb-relation >
<ejb-relation-name>KuchenZutaten</ejb-relation-name>
<ejb-relationship-role >
<ejb-relationship-role-name>zutat-hat-kuchen</ejb-relationship-role-name>
<multiplicity>Many</multiplicity>
<relationship-role-source >
<ejb-name>ZutatAutoPK</ejb-name>
</relationship-role-source>
<cmr-field >
<cmr-field-name>kuchen</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role >
<ejb-relationship-role-name>kuchen-hat-zutaten</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<cascade-delete/>
<relationship-role-source >
<ejb-name>KuchenAutoPK</ejb-name>
</relationship-role-source>
<cmr-field >
<cmr-field-name>zutaten</cmr-field-name>
<cmr-field-type>java.util.Collection</cmr-field-type>
</cmr-field>
</ejb-relationship-role>
</ejb-relation>
</relationships>
Der Auszug aus "jboss-cmp.xml" sieht genauso aus wie im letzten Beispiel.
Anlegen des Webclients
Der Webclient muss die EJB-JARs referenzieren. Dazu in die Eigenschaften des Webmoduls "KuchenZutatAutoPKWeb"
wechseln und unter "J2EE Module Depdencies" das EJB-JAR wählen.
EJB-Verweise festlegen:
Da wir hier kein Servlet verwenden können wir uns den EJB-Verweis nicht per XDoclet generieren lassen.
Also in "Dynamic Web Projects" -> "KuchenZutatAutoPKWeb" -> "WebContent" -> "WEB-INF" -> "web.xml" gehen und
folgendes einfügen:
<ejb-local-ref>
<ejb-ref-name>ejb/ZutatAutoPK</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<local-home>com.knauf.ejb.kuchenzutatautopk.ZutatAutoPKLocalHome</local-home>
<local>com.knauf.ejb.kuchenzutatautopk.ZutatAutoPKLocal</local>
<ejb-link>ZutatAutoPK</ejb-link>
</ejb-local-ref>
<ejb-local-ref>
<ejb-ref-name>ejb/KuchenAutoPK</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<local-home>com.knauf.ejb.kuchenzutatautopk.KuchenAutoPKLocalHome</local-home>
<local>com.knauf.ejb.kuchenzutatautopk.KuchenAutoPKLocal</local>
<ejb-link>KuchenAutoPK</ejb-link>
</ejb-local-ref>
Es müssen vier JSP-Seiten "Kuchen.jsp", "KuchenEdit.jsp", "KuchenZutaten.jsp", "KuchenZutatEdit.jsp" zugefügt werden.
Jetzt die Anwendung nur noch deployen. Sie ist unter
http://localhost:8080/KuchenZutatAutoPKWeb/Kuchen.jsp zu erreichen.
In der Datenbank sieht alles genauso aus wie im "KuchenZutat"-Beispiel, deshalb keine weiteren Screenshots.
Version 1.0.0.0, Stand 31.10.2005
Historie:
1.0.0.0 (31.10.2005): Erstellt