jAbLoK

blog už dávno nejen o javě

JBoss + Xdoclet + Unknown primary key + CMR relation = ?

zanechat komentář »

Za otazníkem v nadpisu se skrývá nejspíše něco jako “spousta zábavy”. Věc se má následovně:

EJB specifikace nám umožňuje ponechat na kontejneru vytváření primárních klíčů, a říká tomu “Unknown primary key” (bod 10.8.3). Co když se rozhodneme něco takového zkusit v praxi (s aplikačním serverem JBoss 4.0.1)?

Nejprve se popereme s implementací “neznámého” primárního klíče.

Člověk by řekl, že postačí v souladu se specifikací definovat návratový typ příslušé findByPrimaryKey metody jako java.lang.Object, stejný typ dát příslušnému CMP poli a navíc třídu i pole patřičně otagovat Xdocletem (u třídy @jboss.unknown-pk a @ejb.pk class = "java.lang.Object" generate = "false", u get metody pak @ejb:persistent-field, @ejb:pk-field a @ejb:interface-method view-type="local").

A houbeles — JBossův CMP plugin nerozpozná, že deklarovaný “unknown primary key” je totožný s deklarovaným CMP primárním klíčem, a tedy generuje dotazy jako insert into tabulka (pk field, pkfield, ...). Zkrátka vidí dva sloupce, od čehož se odvíjejí rozličná chybová hlášení, od pochopitelné stížnosti relační databáze na zdvojené jméno sloupce v insert dotazu, až po mysteriózní zamyšlení aplikačního serveru na téma nevhodnosti složených primárních klíčů ve scénáři “unknown primary key”.

Co s tím? Zlenivěn Xdocletem přeskakuji studium JBoss-specific deployment descriptoru (možná chyba ;) ) a rovnou sahám po manuálu k Xdocletu. Nabízí pouze uvést JBoss specific tagem název databázového sloupce sloužícího jako PK, to pochopitelně dělám, ale JBoss si z toho (vcelku pochopitelně) souvislost neznámého klíče a specifikovaného CMP fieldu odvodit nedokáže. Navíc při generování SQL příkazu INSERT se snaží vkládat primární klíč coby null namísto toho, aby se o něm vůbec nezmiňoval.

Napadá mě CMP field pro primární klíč vypustit, a vida, najednou vše funguje. Primární klíč se stává opravdu doslova neznámým — v důsledku to znamená, že hodnotu klíče musím lovit přes ruku z EntityContextu získaného callback metodou, ale tím se trápit nebudeme.

Nicméně nyní nás čeká úkol číslo 2 — definovat mezi takovýmito entitami relaci.

Napohled nic těžkého, dokud si neuvědomíme, že v descriptoru aplikačního serveru musíme definovat propojovací sloupce — a nyní na nás dopadá důsledek předminulého odstavce: co je vlastně primárním klíčem, když jsme jeho CMP pole zavrhli?

Po marném Googlování a několika naivního pokusech cosi nastřelit nezbývá než využít dostupnosti zdrojových kódů JBosse a ladících možností Eclipse. Po pár breakpointech je situace jasná:

Vytvoříme-li “unknown primary key” výše popsaným způsobem, JBoss si interně zavede pole s názvem JménoBeany_upk.
Toto po chvíli úspěšně ověřuju na stránce JBossích odštěpenců z Core Developers Network

Uf.

Stále si říkám, že by nebylo od věci tam pole pro primání klíč zavést. Neustále se ale opakují problémy se zdvojenými poli v dotazu či nadbytečným uvádění primárního klíče v INSERT dotazu.

Takže výsledný kód je:

/**
* @ejb.bean name="Something" type="CMP" cmp-version="2.x" view-type="local"
* @jboss.entity-command name="postgresql-fetch-seq"
*     class="org.jboss.ejb.plugins.cmp.jdbc.keygen.JDBCPostgreSQLCreateCommand"
* @jboss.unknown-pk auto-increment = "true" column-name="somethingId"
*     jdbc-type="INTEGER" sql-type="INTEGER"
*     class="java.lang.Integer"
* @ejb.pk class = "java.lang.Object" generate = "false"
*/
public abstract class SomethingEJB implements EntityBean {

/**
* @ejb.interface-method view-type="local"
* @ejb.relation name="Something_SomethingElse"
*     role-name="something-has-somethingelse"
*     target-ejb="SomethingElse"
*     target-role-name="somethingelse-has-something "
* @jboss.relation related-pk-field=&quot;SomethingElse<strong>_upk</strong>&quot;
*     fk-column=&quot;assignedSomethingElse&quot;
*/
public abstract LocalSomethingElse getSomethingElse ();

// other stuff comes here

}

(Jde o dvě entity beans — Something a SomethingElse, obě mají databází generovaný (a z pohledu EJB specifikace “unknown”) primární klíč. Pro jednoduchost jsem uvedl zdrojový kód pouze jedné z nich, která obsahuje jednosměrnou relaci getSomethingElse().)

Written by Pavel Kolesnikov

duben 6, 2005 na 9:18 dop.

Zasláno do Java

Tagged with , ,

Zanechat odpověď