users@glassfish.java.net

JPA - One-To-Many relationship query problem

From: <glassfish_at_javadesktop.org>
Date: Thu, 31 Jan 2008 13:54:07 PST

Hi there,

I am using glassfish-toplink JPA implementation in a standalone application. I am trying to map one to many relationships in two different ways. I am having problems both ways. The class and table relationship I am trying to map looks like this.
Class CA is mapped to the table A below. CA has a one to many relationship mapped to CB, foreign key being aId.
Class CA {
 List<CB> list;
 int aId;
 String col1;
 String col2;
}

Table A
id aId
String col1
String col2

Class CB is mapped to table B below. Class CB has a many to one relationship with CA. Its mapped by aId.
Class CB{
int aId;
String path;
String x
String y;
}

Table B
id aId
id path
String x
String y

When I load this mapping, modeled in orm.xml file, I get an error. Looks like the problem is caused by the foreign key aId also being a part of composite primary key along with path. The actual orm.xml snippet with actual table and class names is below.

[b]Error [/b]
An incompatible mapping has been encountered between [class com.bmc.arsys.server.persistence.ListMenuType] and [class com.bmc.arsys.server.persistence.ListMenuItemType]. This usually occurs when the cardinality of a mapping does not correspond with the cardinality of its backpointer.

[b]orm.xml snippet. [/b]
<entity class="com.bmc.arsys.server.persistence.ListMenuType" access="FIELD">
                <table name="char_menu"/>
                <discriminator-value>1</discriminator-value>
                <attributes>
                        <one-to-many name="listMenuItem" target-entity="com.bmc.arsys.server.persistence.ListMenuItemType" mapped-by="charMenuId">

                                <join-column name="charMenuId"/>
                                <cascade>
                                        <cascade-all/>
                                        <cascade-persist/>
                                        <cascade-merge/>
                                        <cascade-remove/>
                                        <cascade-refresh/>
                                </cascade>
                        </one-to-many>
                </attributes>
                
        </entity>

        <entity class="com.bmc.arsys.server.persistence.ListMenuItemType" access="FIELD">
                <table name="char_menu_list"/>
                <attributes>
                        <id name="charMenuId"><column name="charMenuId"/></id>
                        <id name="path"><column name="path"/></id>
                        <many-to-one name="charMenuId">
                                <join-column name="charMenuId"/>
                        </many-to-one>
                </attributes>
        </entity>

Is this a limitation (that I cant use part of a composite primary key as a foreign key in a one-to-many relationship mapping) with toplink jpa implementation?

2 The second option I tried to get around the problem above is this. I map this relationship by creating a in between join table, and use this kind of mapping.

[b]orm.xml snippet[/b]
        <entity class="com.bmc.arsys.server.persistence.ListMenuType" access="FIELD">
                <table name="char_menu"/>
                <discriminator-value>1</discriminator-value>
                <attributes>
                        <one-to-many name="listMenuItem" target-entity="com.bmc.arsys.server.persistence.ListMenuItemType" >
                                <join-table name="char_menu_list_join">
                                        <join-column name="charMenuId" referenced-column-name="charMenuId" table="char_menu"/>
                                        <inverse-join-column name="charMenuId" referenced-column-name="charMenuId" table="char_menu_list"/>
                                        <inverse-join-column name="path" referenced-column-name="path" table="char_menu_list"/>
                                </join-table>

                                <cascade>
                                        <cascade-all/>
                                        <cascade-persist/>
                                        <cascade-merge/>
                                        <cascade-remove/>
                                        <cascade-refresh/>
                                </cascade>
                        </one-to-many>
                </attributes>
                
        </entity>

        <entity class="com.bmc.arsys.server.persistence.ListMenuItemType" access="FIELD">
                <table name="char_menu_list"/>
                <attributes>
                        <id name="charMenuId"><column name="charMenuId"/></id>
                        <id name="path"><column name="path"/></id>
                </attributes>
        </entity>

This mapping loads fine and I get the results from the query, but the returned ListMenuType object doesnt have the listMenuItem populated. The list (that captures the one to many relationship) is empty. I can see these log messages from top link logging. If I use the second SQL statement in query analyzer, it actually works, I do get a resultset that would form the one-to-many results list. But yet, this is not populated in the object that is returned as a result of the query. Any ideas? Is there something wrong with what I am doing?

[b]Toplink log[/b]

[TopLink Fine]: 2008.01.31 12:14:34.798--ServerSession(31291190)--Connection(32126195)--Thread(Thread[TCP server transport connection thread,5,main])--SELECT t0.charMenuId, t0.menuType, t0.OWNER, t0.LASTCHANGED, t0.OBJPROP, t0.TIMESTAMP, t0.SMOBJPROP, t0.CHANGEDIARY, t0.VERSION, t0.HELPTEXT, t0.NAME, t0.SAFEGUARD, t0.REFRESHCODE, t1.charMenuId, t1.LABELINDEX5, t1.PATH, t1.VALUEINDEX, t1.LABELINDEX, t1.SQLCMDSHORT, t1.LABELINDEX3, t1.SQLCMDLONG, t1.SERVER, t1.KEYWORDLIST, t1.LABELINDEX4, t1.PARAMETERLIST, t1.LABELINDEX2, t1.EXTERNLIST, t2.charMenuId, t2.NAMETYPE, t2.VALUEFORMAT, t2.SERVER, t2.STRUCTSUBTYPE, t2.PATH, t2.ARSCHEMA, t2.STRUCTTYPE, t2.HIDDENTOO, t3.charMenuId, t3.LABELFIELD5, t3.VALUEFIELD, t3.SERVER, t3.SORTONLABEL, t3.LABELFIELD, t3.KEYWORDLIST, t3.LABELFIELD3, t3.PARAMETERLIST, t3.PATH, t3.EXTERNLIST, t3.LABELFIELD2, t3.SAMPLESCHEMA, t3.ARSCHEMA, t3.SAMPLESERVER, t3.LABELFIELD4, t3.QUERYSHORT, t3.QUERYLONG, t4.charMenuId, t4.FILELOCATION, t4.PATH, t4.FILENAME FROM char_menu t0 LEFT OUTER JOIN char_menu_sql t1 ON (t1.charMenuId = t0.charMenuId) LEFT OUTER JOIN char_menu_dd t2 ON (t2.charMenuId = t0.charMenuId) LEFT OUTER JOIN char_menu_query t3 ON (t3.charMenuId = t0.charMenuId) LEFT OUTER JOIN char_menu_file t4 ON (t4.charMenuId = t0.charMenuId) WHERE (t0.NAME = ?)
        bind => [MsgCat: MsgType Menu]
[TopLink Fine]: 2008.01.31 12:14:37.876--ServerSession(31291190)--Connection(28723276)--Thread(Thread[TCP server transport connection thread,5,main])--SELECT t1.charMenuId, t1.path, t1.LABEL, t1.CHILDTYPE, t1.VALUE FROM char_menu_list_join t0, char_menu_list t1 WHERE ((t0.charMenuId = ?) AND ((t1.path = t0.path) AND (t1.charMenuId = t0.charMenuId)))
        bind => [1]
[Message sent by forum member 'pmysore' (pmysore)]

http://forums.java.net/jive/thread.jspa?messageID=256864