Primary Key Vergabe

Status
Nicht offen für weitere Antworten.

Oskar

Aktives Mitglied
Hallo ich schon wieder...

Wenn ich ein Entitybean definiere übernimmt dies die selbe Struktur wie auf der DB (was die Felder der Tabelle angeht). Auf der DB (mySQL) habe ich in der Tabelle ein Primarykey Feld vom Typ INTEGER. Dieses Feld wird im EJB durch ein Feld vom Typ java.lang.Integer dargestellt.

Mein Problem:
Wie kann ich in der ejbCreate() Methode einen primary Key sauber erstellen? Gibt es hierfür eine Beispielhafte Implementierung? Wie lößt ihr die Vergabe von Primarykeys? ???:L

Ich suche schon zum zweiten mal nach einer Lösung und habe bisher keine Idee einer Lösung geschweige denn einen Ansatz.

Danke im Voraus
Oskar
 
G

Guest

Gast
Siehe Statement.executeUpdate(String sql, int autoGeneratedKeys),
Statement.RETURN_GENERATED_KEYS
und Statement.getGeneratedKeys()

Alternative: "Sequence-Pattern"
 

foobar

Top Contributor
Um in einer CMP Entity Bean, unter Verwendung von Jboss, an den autoincrement Wert zu gelangen mußt du folgendes machen:
jboss-cmp-jdbc.xml:
Code:
<jbosscmp-jdbc>
   <defaults>
......	
     <entity-command name="mysql-get-generated-keys"/>
.......
   </defaults>
.....
<entity>
         <ejb-name>OrderBean</ejb-name>
         <table-name>orders</table-name>
    	<cmp-field>
       		<field-name>orderID</field-name>
			<column-name>ord_id</column-name>
	    </cmp-field>
	   <cmp-field>
			  <field-name>orderDate</field-name>
			  <column-name>ord_date</column-name>
	    </cmp-field>
		<cmp-field>
			  <field-name>customerName</field-name>
			  <column-name>ord_customer_name</column-name>
	    </cmp-field>
		<unknown-pk>
			<unknown-pk-class>java.lang.Integer</unknown-pk-class>
		   <field-name>orderID</field-name>
			<column-name>ord_id</column-name>
			<jdbc-type>INTEGER</jdbc-type>
			<sql-type>INTEGER</sql-type>
			<auto-increment/>
		</unknown-pk>
	</entity>		  
....

ejb-jar.xml
Code:
.......
<entity>
      <description></description>
      <ejb-name>OrderBean</ejb-name>
      <local-home>myshop.ejbs.entitie.OrderLocalHome</local-home>
      <local>myshop.ejbs.entitie.OrderLocal</local>
	  <ejb-class>myshop.ejbs.entitie.OrderBean</ejb-class>
      <persistence-type>Container</persistence-type>
      <prim-key-class>java.lang.Integer</prim-key-class>
      <reentrant>True</reentrant>
    <cmp-version>2.x</cmp-version>
    <abstract-schema-name>OrderBean</abstract-schema-name>
    <cmp-field>
       <field-name>orderID</field-name>
    </cmp-field>
	   <cmp-field>
       <field-name>customerName</field-name>
    </cmp-field>
	<cmp-field>
       <field-name>orderDate</field-name>
    </cmp-field>
	<primkey-field>orderID</primkey-field>
.....
 
G

Guest

Gast
@foobar
Ich nahm an, er meint BMP, nicht CMP, da:
Oskar hat gesagt.:
...Wie kann ich in der ejbCreate() Methode einen primary Key sauber erstellen?...
In CMP wird kein Primary-Key erstellt bzw. die ejbCreate-Methode (2.x Spezifikation) sollte null
zurückgeben, daher ging ich davon aus, dass er BMP gemeint hat.
Nur mal so als Anmerkung... :wink:
 

Oskar

Aktives Mitglied
...so gut.

Danke für die Hilfe. Werde das mit den Deployment descriptoren mal ausprobieren.

@Gast
In CMP wird kein Primary-Key erstellt bzw. die ejbCreate-Methode (2.x Spezifikation) sollte null
zurückgeben, daher ging ich davon aus, dass er BMP gemeint hat.

Sorry hatte ich vergessen. Ich meinte CMP.
Also dass ich in der ejbCreate() Methode keinen Primarykey zurückgebe ist mir bewußt.
Nur wenn in der ejbCreate() Methode das Element erstellt und auf die DB geschrieben wird, dann müssen alle Felder gefüllt werden, die auf der DB als NOT NULL deklariert wurden (sonst gibt es scheene SQL Exceptions :x )
Daher muss ich doch auch hier ein evtl. PK Feld füllen. Es sei denn ich gehe davon aus, dass der PK beim Aufruf von ejbCreate() als Parameter übergeben wird, was ich persönlich irgendwie schlecht finde, denn was geht es den Nutzer des EJB an wie der PK gesetzt wird.

Naja noch mehr Verwirrung.

So far...
Oskar
 

Oskar

Aktives Mitglied
Ich muss nochmal was fragen...

Also wenn ich die Änderungen in den Meta Informationen wie beschrieben vornehme, legt er mir beim Ausführen der create() Methode ein neues Element auf der Datenbank an, und zählt auch schön brav den Auto-Increment Wert hoch.

Laut Doku Stellt JBoss über die Namensgleichheit zwischen dem unknown-pk field und einem existierenden cmp-field eine Inhaltliche Beziehung her. Also gehe ich davon aus, dass nach dem erstellen der Daten auf der DB auch die Inhalte von der DB in dem definierten Feld sind.

Nun ist es so, dass er den Daten satz zwar auf der DB anlegt, jedoch das Primary-Key Feld des EJBs nicht füllt, und mir dann eine Exception wirft, die besagt

Code:
 Primary key for created instance is null

Kann es daran liegen, dass ich einmal ein unknown-pk field definiere und andererseits eine pk-field für mein EJB anlege? (auf welches das unknown-pk field referenziert)

Wie sollte denn der Inhalt der auf der DB erstellt wird in das PK Field des EJBs kommen?

Danke im Voraus
Oskar
 

foobar

Top Contributor
Wie sollte denn der Inhalt der auf der DB erstellt wird in das PK Field des EJBs kommen?
In der jbosscmp-jdbc.xml werden doch alle benötigten Informationen angegeben (field_name, column_name etc.).
Wie sieht denn deine EntityBean aus? Welche Exception wird wann geworfen?
 

Oskar

Aktives Mitglied
Also...

meine jbosscmp-jdbc.xml sieht wie folgt aus:

Code:
<jbosscmp-jdbc>
   <defaults>
     <datasource>java:ForumDS</datasource>
     <datasource-mapping>mySQL</datasource-mapping>
     <entity-command name="mysql-get-generated-keys" />
   </defaults>

   <enterprise-beans>

        <entity>
         <ejb-name>User</ejb-name>
         <create-table>no</create-table>
         <remove-table>no</remove-table>
		
         <table-name>forum_user</table-name>

         <cmp-field>
            <field-name>userId</field-name>
            <column-name>user_id</column-name>
            <jdbc-type>INTEGER</jdbc-type>
            <sql-type>INTEGER</sql-type>
        </cmp-field>
         <cmp-field>
            <field-name>nickName</field-name>
            <column-name>nick_name</column-name>
            <jdbc-type>VARCHAR</jdbc-type>
            <sql-type>VARCHAR</sql-type>
        </cmp-field>
         <cmp-field>
            <field-name>EMail</field-name>
            <column-name>e_mail</column-name>
            <jdbc-type>VARCHAR</jdbc-type>
            <sql-type>VARCHAR</sql-type>
        </cmp-field>
		<unknown-pk>
	         <unknown-pk-class>java.lang.Integer</unknown-pk-class>
	         <field-name>userId</field-name>
	         <column-name>user_id</column-name>
	         <jdbc-type>INTEGER</jdbc-type>
	         <sql-type>INTEGER</sql-type>
	         <auto-increment />
      </unknown-pk>
      </entity>
   </enterprise-beans>
</jbosscmp-jdbc>

Das Feld, das als PrimKey verwendet werden soll ist userId.

Die ejb-jar.xml sieht do aus:


Code:
<ejb-jar >

   <description><![CDATA[No Description.]]></description>
   <display-name>Generated by XDoclet</display-name>

   <enterprise-beans>

     <entity >
         <description>Forum User</description>

         <ejb-name>User</ejb-name>

         <home>user.UserHome</home>
         <remote>user.User</remote>
         <local-home>user.UserLocalHome</local-home>
         <local>user.UserLocal</local>

         <ejb-class>user.UserCMP</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>java.lang.Integer</prim-key-class>
         <reentrant>True</reentrant>
         <cmp-version>2.x</cmp-version>
         <abstract-schema-name>forumUser</abstract-schema-name>
         <cmp-field >
            <description>User Id</description>
            <field-name>userId</field-name>
         </cmp-field>
         <cmp-field >
            <description>Nick Name</description>
            <field-name>nickName</field-name>
         </cmp-field>
         <cmp-field >
            <description>E-Mail Adress</description>
            <field-name>EMail</field-name>
         </cmp-field>
          <primkey-field>userId</primkey-field>

         <query>
            <query-method>
               <method-name>findAll</method-name>
               <method-params>
               </method-params>
            </query-method>
            <ejb-ql><![CDATA[SELECT OBJECT(a) FROM forum as a]]></ejb-ql>
         </query>
      </entity>

   </enterprise-beans>
   <assembly-descriptor >
   </assembly-descriptor>

</ejb-jar>

Hier ist userId als Prim key definiert.

Die Exception wird geworfen wenn ich in einem Servlet über home.create() eine Instanz des EJBs erzeuge. Sie lautet

Code:
StandardWrapperValve[CreateUser]: Servlet.service() for servlet CreateUser threw exception
javax.servlet.ServletException: Could not create User! Primary key for created instance is null.


Wie gesagt ein Blick auf die MySQL DB zeigt, dass die Daten erstellt werden.
Ich hoffe jetzt ist die Situation klar.

Oskar
 

foobar

Top Contributor
Also die Deploymentdescriptoren sehen in Ordnung aus. Wie sieht denn der Code deiner EntityBean aus? Was machst du in der Create-Methode?
 

Oskar

Aktives Mitglied
Also ich vermute jetzt wirds peinlich... :oops:

Bisher mache ich in der ejbCreate() Methode noch gar nix. Sollte ich? Muss ich da irgeneine Funktion auf der DB aufrufen?

Ich dachte das übernimmt die EJB Implementierung für mich wenn die Descriptoren stimmen.

Hm vielleicht ist es dann ja ganz einfach...

Oskar
 

foobar

Top Contributor
Du mußt zumindest die übergebenen Werte an die entsprechenden cmp-Felder weiterleiten z.b. so:
Code:
public Integer ejbCreate(String name, String password) throws CreateException
{
    this.setName( name );
    this.setPassword( password );
    return null;
}
 

Bleiglanz

Gesperrter Benutzer
ahhhh,

wenn du deine PKs vom Container verwalten lassen willst, dann MUSS der Primary Key vom Typ Object sein, lies mal die Spec

also:

<prim-key-class>java.lang.Object</prim-key-class>

Nebenbei: mit eine der schlimmsten Auslassungen in der EJB-Spec überhaupt, es gibt da allerhand Literatur dazu, wie man so einen Key-Generator von Hand nachimplementiert - ist aber alles furchtbarer Zeugs....

trotzdem nehme ich nie die SERIAL oder AUTOINCREMENT oder sonstwas der Datenbank her, weil es mir lieber ist, wenn innerhalb der Anwendung der PK vom richtigen Typ ist
 

Bleiglanz

Gesperrter Benutzer
naja, da gibts ja viele schöne "ideen" dazu
mal ein high-low-schema (wie z.B. bei hibernate) usw. usf.

leider habe ich noch keine wirklich perfekte lösung gefunden, die

- im ejb-umfeld arbeitet
- transaktionssicher ist
- keine nebenläufigkeitsprobleme aufwirf
- nicht unbedingt den allerhöchsten Isolationslevel erfordert
- einigermassen einfach (programmatisch) zu bedienenist

eigentlich mach ich jedes mal was anderes :)

zuletzt hab ich mir eine dummy-Tabelle genommen mit einer SEQUENCE, aus der ich dann mit SELECT nextkey per direktem SQL-Zugriff immer neue nummern generieren lasse (und zwar ein globaler Zähler für ALLE Entities)

bei einer DuplicateKeyEx nehm ich einfach den nächsten...

ist nicht perfekt, aber irgendwie "Offline" ein "Pseudo-Singleton" zu implementieren ist mir wirklich zu aufwendig

Das bringt mich doch gleich zu einer weiteren schlimmen Auslassung in der EJB-Spec: kein ApplicationScope - während man für Webanwendungen wenigstens noch sowas wie den ServletContext hat, ist für ejb.jars keinerlei "globaler" Context vorgesehen, ahhhhhh
 

Oskar

Aktives Mitglied
Hallo zusammen,

nach fast endlosen Kämpfen mit der IDE und den Descriptoren hier die Lösung wie es klappt. Vielleicht interessiert es ja noch jemanden.

ejb-jar.xml
Code:
<ejb-jar >
   <enterprise-beans>

      <entity >
         <display-name>UserBean</display-name>
         <ejb-name>User</ejb-name>

         <home>user.UserHome</home>
         <remote>user.User</remote>

         <ejb-class>user.UserCMP</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>java.lang.Object</prim-key-class>
         <reentrant>false</reentrant>
         <cmp-version>2.x</cmp-version>
         <cmp-field >
            <field-name>userId</field-name>
         </cmp-field>
         <cmp-field >
            <field-name>EMail</field-name>
         </cmp-field>
         <cmp-field >
            <field-name>nickName</field-name>
         </cmp-field>
         <cmp-field >
            <field-name>password</field-name>
         </cmp-field>

      </entity>
   </enterprise-beans>

   <assembly-descriptor >
   </assembly-descriptor>

</ejb-jar>

jbosscmp-jdbc.xml

Code:
<jbosscmp-jdbc>
   <defaults>
     <datasource>java:ForumDS</datasource>
     <datasource-mapping>mySQL</datasource-mapping>
     <create-table>false</create-table>
     <remove-table>false</remove-table>
   </defaults>

   <enterprise-beans>
      <entity>
         <ejb-name>User</ejb-name>

         <table-name>forum_user</table-name>

         <cmp-field>
            <field-name>userId</field-name>
			<read-only>true</read-only>
            <column-name>user_id</column-name>
            <jdbc-type>INTEGER</jdbc-type>
            <sql-type>INTEGER</sql-type>
	    <auto-increment/>
        </cmp-field>
         <cmp-field>
            <field-name>EMail</field-name>
            <column-name>e_mail</column-name>
            <jdbc-type>VARCHAR</jdbc-type>
            <sql-type>VARCHAR(45)</sql-type>
        </cmp-field>
         <cmp-field>
            <field-name>nickName</field-name>
            <column-name>nick_name</column-name>
            <jdbc-type>VARCHAR</jdbc-type>
            <sql-type>VARCHAR(45)</sql-type>
        </cmp-field>
         <cmp-field>
            <field-name>password</field-name>
            <column-name>password</column-name>
            <jdbc-type>VARCHAR</jdbc-type>
            <sql-type>VARCHAR(12)</sql-type>
        </cmp-field>

	<unknown-pk>
		<unknown-pk-class>java.lang.Object</unknown-pk-class>
		<field-name>userId</field-name>
		<column-name>user_id</column-name>
		<jdbc-type>INTEGER</jdbc-type>
		<sql-type>INTEGER</sql-type>
		<auto-increment/>
	</unknown-pk>

	<entity-command name="mysql-get-generated-keys">
	</entity-command>
      </entity>

   </enterprise-beans>

</jbosscmp-jdbc>

Danke für dir Tipps.

So far says
Oskar
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen

Ähnliche Java Themen


Oben