on 10-27-2004 3:43 PM
Curious to know whether someone has been able to set up a many to many relationship between two entity beans.
I have been struggling with this for days now and I can't get it to work.
In my test project I have two entity beans, resp. Consultant and Solution.
Consultant has a cmr field called 'solutions', which is a collection object from the opposite side (Solution).
This is the source of the ejb-jar.xml file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
<description>EJB JAR description</description>
<display-name>EJB JAR</display-name>
<enterprise-beans>
<session>
<ejb-name>ProfilerBean</ejb-name>
<home>com.atosorigin.tcc.testing.ejbses.profiling.ProfilerHome</home>
<remote>com.atosorigin.tcc.testing.ejbses.profiling.Profiler</remote>
<local-home>com.atosorigin.tcc.testing.ejbses.profiling.ProfilerLocalHome</local-home>
<local>com.atosorigin.tcc.testing.ejbses.profiling.ProfilerLocal</local>
<ejb-class>com.atosorigin.tcc.testing.ejbses.profiling.ProfilerBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<ejb-local-ref>
<ejb-ref-name>EJBTesting/Solution</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<local-home>com.atosorigin.tcc.testing.ejbcmp.profiling.SolutionLocalHome</local-home>
<local>com.atosorigin.tcc.testing.ejbcmp.profiling.SolutionLocal</local>
<ejb-link>SolutionBean</ejb-link>
</ejb-local-ref>
<ejb-local-ref>
<ejb-ref-name>EJBTesting/Consultant</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<local-home>com.atosorigin.tcc.testing.ejbcmp.profiling.ConsultantLocalHome</local-home>
<local>com.atosorigin.tcc.testing.ejbcmp.profiling.ConsultantLocal</local>
<ejb-link>ConsultantBean</ejb-link>
</ejb-local-ref>
</session>
<entity>
<ejb-name>ConsultantBean</ejb-name>
<home>com.atosorigin.tcc.testing.ejbcmp.profiling.ConsultantHome</home>
<remote>com.atosorigin.tcc.testing.ejbcmp.profiling.Consultant</remote>
<local-home>com.atosorigin.tcc.testing.ejbcmp.profiling.ConsultantLocalHome</local-home>
<local>com.atosorigin.tcc.testing.ejbcmp.profiling.ConsultantLocal</local>
<ejb-class>com.atosorigin.tcc.testing.ejbcmp.profiling.ConsultantBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Consultant</abstract-schema-name>
<cmp-field>
<field-name>firstname</field-name>
</cmp-field>
<cmp-field>
<field-name>lastname</field-name>
</cmp-field>
<cmp-field>
<field-name>country</field-name>
</cmp-field>
<cmp-field>
<field-name>id</field-name>
</cmp-field>
<primkey-field>id</primkey-field>
<query>
<query-method>
<method-name>findBySolution</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</query-method>
<ejb-ql>SELECT Object(c) FROM Consultant AS c,
IN(c.solutions) s WHERE s.id = ?1 </ejb-ql>
</query>
</entity>
<entity>
<ejb-name>SolutionBean</ejb-name>
<home>com.atosorigin.tcc.testing.ejbcmp.profiling.SolutionHome</home>
<remote>com.atosorigin.tcc.testing.ejbcmp.profiling.Solution</remote>
<local-home>com.atosorigin.tcc.testing.ejbcmp.profiling.SolutionLocalHome</local-home>
<local>com.atosorigin.tcc.testing.ejbcmp.profiling.SolutionLocal</local>
<ejb-class>com.atosorigin.tcc.testing.ejbcmp.profiling.SolutionBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Solution</abstract-schema-name>
<cmp-field>
<field-name>description</field-name>
</cmp-field>
<cmp-field>
<field-name>name</field-name>
</cmp-field>
<cmp-field>
<field-name>parent</field-name>
</cmp-field>
<cmp-field>
<field-name>id</field-name>
</cmp-field>
<primkey-field>id</primkey-field>
<query>
<query-method>
<method-name>findChildSolutions</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</query-method>
<ejb-ql>SELECT Object(s) FROM Solution AS s WHERE
s.parent = ?1</ejb-ql>
</query>
<query>
<query-method>
<method-name>findTopLevelSolutions</method-name>
<method-params/>
</query-method>
<ejb-ql>Select Object(s) FROM Solution AS s WHERE
(s.parent = 'none')</ejb-ql>
</query>
</entity>
</enterprise-beans>
<relationships>
<ejb-relation>
<description>A consultant may have one or more areas of expertise</description>
<ejb-relation-name>Consultant_Solutions</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>com.atosorigin.tcc.testing.ejbcmp.profiling.ConsultantBean</ejb-relationship-role-name>
<multiplicity>Many</multiplicity>
<relationship-role-source>
<ejb-name>ConsultantBean</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>solutions</cmr-field-name>
<cmr-field-type>java.util.Collection</cmr-field-type>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>com.atosorigin.tcc.testing.ejbcmp.profiling.SolutionBean</ejb-relationship-role-name>
<multiplicity>Many</multiplicity>
<relationship-role-source>
<ejb-name>SolutionBean</ejb-name>
</relationship-role-source>
</ejb-relationship-role>
</ejb-relation>
</relationships>
<assembly-descriptor>
<container-transaction>
<description>container-transaction</description>
<method>
<ejb-name>SolutionBean</ejb-name>
<method-name>*</method-name>
</method>
<method>
<ejb-name>ProfilerBean</ejb-name>
<method-name>*</method-name>
</method>
<method>
<ejb-name>ConsultantBean</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
I created a stateless session bean as a business facade for the two entity beans. I then created a webservice to test the beans.
What works :
- create a consultant
- get a consultant
- create a solution
- get a solution
(basically everything that doesn't involve the relationship field.
However, what doesn't work is the method call assignSolution:
- assign solution : this is implemented as follows
/**
Business Method.
*/
public void assignSolution(String consultantID, String solutionID)
throws ProfilingException {
// TODO : Implement
ConsultantLocal cons = null;
SolutionLocal sol = null;
try {
cons = consHome.findByPrimaryKey(consultantID);
sol = solHome.findByPrimaryKey(solutionID);
Collection solutions = cons.getSolutions();
solutions.add(sol);
//sol.getConsultants().add(cons);
} catch (FinderException ex) {
ex.printStackTrace();
throw new ProfilingException("failed to retrieve data from DB", ex);
}
}
As you can see I am trying to use the CM Relationship in this methhod. Adding the solution to a consultant should be as simple as adding a solution object to the collection retrieved with the getSolutions accessor. The Container is expected to persist the information in my MAXDB database.
However this doesn't happen.
The ORM details as defined in the persistent.xml follows :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persistent-ejb-map SYSTEM "persistent.dtd">
<persistent-ejb-map>
<locking
type="Table"/>
<db-properties>
<data-source-name>TCC_PORTAL_PROFILER</data-source-name>
<database-vendor
name="SAPDB"/>
</db-properties>
<entity-beans>
<entity-bean>
<ejb-name>ConsultantBean</ejb-name>
<table-name>PFL_CONSULTANTS</table-name>
<field-map
key-type="NoKey">
<field-name>firstname</field-name>
<column>
<column-name>FIRSTNAME</column-name>
</column>
</field-map>
<field-map
key-type="NoKey">
<field-name>lastname</field-name>
<column>
<column-name>LASTNAME</column-name>
</column>
</field-map>
<field-map
key-type="NoKey">
<field-name>country</field-name>
<column>
<column-name>COUNTRY</column-name>
</column>
</field-map>
<field-map
key-type="PrimaryKey">
<field-name>id</field-name>
<column>
<column-name>ID</column-name>
</column>
</field-map>
<finder-descriptor>
<method-name>findBySolution</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
<load-selected-objects
lock="read"/>
</finder-descriptor>
</entity-bean>
<entity-bean>
<ejb-name>SolutionBean</ejb-name>
<table-name>PFL_SAPSOLUTIONS</table-name>
<field-map
key-type="NoKey">
<field-name>description</field-name>
<column>
<column-name>DESCRIPTION</column-name>
</column>
</field-map>
<field-map
key-type="NoKey">
<field-name>name</field-name>
<column>
<column-name>NAME</column-name>
</column>
</field-map>
<field-map
key-type="NoKey">
<field-name>parent</field-name>
<column>
<column-name>PARENTID</column-name>
</column>
</field-map>
<field-map
key-type="PrimaryKey">
<field-name>id</field-name>
<column>
<column-name>ID</column-name>
</column>
</field-map>
<finder-descriptor>
<method-name>findChildSolutions</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
<load-selected-objects
lock="read"/>
</finder-descriptor>
<finder-descriptor>
<method-name>findTopLevelSolutions</method-name>
<method-params/>
<load-selected-objects
lock="read"/>
</finder-descriptor>
</entity-bean>
</entity-beans>
<relationships>
<table-relation>
<help-table>PFL_CONS_SOL_MAP</help-table>
<table-relationship-role
key-type="PrimaryKey">
<ejb-name>ConsultantBean</ejb-name>
<cmr-field>solutions</cmr-field>
<fk-column>
<column-name>CONSULTANTID</column-name>
<pk-field-name>id</pk-field-name>
</fk-column>
</table-relationship-role>
<table-relationship-role
key-type="PrimaryKey">
<ejb-name>SolutionBean</ejb-name>
<fk-column>
<column-name>SOLUTIONID</column-name>
<pk-field-name>id</pk-field-name>
</fk-column>
</table-relationship-role>
</table-relation>
</relationships>
</persistent-ejb-map>
The error in the default trace file when calling the method states, there is an "inconsistency in the number of primary keys". Details follow.
#
#1.5#000F1F188E5C004400000000000010480003E76C80EFD57A#1098880364327#com.sap.engine.services.ejb#com.atosorigin.tcc/EJBCMPProfilingTest#com.sap.engine.services.ejb#Guest#2####4d2b2370281411d9a40d000f1f188e5c#SAPEngine_Application_Thread[impl:3]_31##0#0#Error##Java###
[EXCEPTION]
#1#com.sap.engine.services.ejb.exceptions.BaseRemoteException: Exception in method assignSolution.
at com.atosorigin.tcc.testing.ejbses.profiling.ProfilerObjectImpl0.assignSolution(ProfilerObjectImpl0.java:822)
at com.atosorigin.tcc.testing.ejbses.profiling.Profiler_Stub.assignSolution(Profiler_Stub.java:533)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at com.sap.engine.services.ejb.session.stateless_sp5.ObjectStubProxyImpl.invoke(ObjectStubProxyImpl.java:187)
at $Proxy73.assignSolution(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at com.sap.engine.services.webservices.runtime.EJBImplementationContainer.invokeMethod(EJBImplementationContainer.java:126)
at com.sap.engine.services.webservices.runtime.RuntimeProcessor.process(RuntimeProcessor.java:146)
at com.sap.engine.services.webservices.runtime.RuntimeProcessor.process(RuntimeProcessor.java:68)
at com.sap.engine.services.webservices.runtime.servlet.ServletDispatcherImpl.doPost(ServletDispatcherImpl.java:92)
at SoapServlet.doPost(SoapServlet.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at com.sap.engine.services.servlets_jsp.server.HttpHandlerImpl.runServlet(HttpHandlerImpl.java:385)
at com.sap.engine.services.servlets_jsp.server.HttpHandlerImpl.handleRequest(HttpHandlerImpl.java:263)
at com.sap.engine.services.httpserver.server.RequestAnalizer.startServlet(RequestAnalizer.java:339)
at com.sap.engine.services.httpserver.server.RequestAnalizer.startServlet(RequestAnalizer.java:317)
at com.sap.engine.services.httpserver.server.RequestAnalizer.invokeWebContainer(RequestAnalizer.java:810)
at com.sap.engine.services.httpserver.server.RequestAnalizer.handle(RequestAnalizer.java:238)
at com.sap.engine.services.httpserver.server.Client.handle(Client.java:92)
at com.sap.engine.services.httpserver.server.Processor.request(Processor.java:147)
at com.sap.engine.core.service630.context.cluster.session.ApplicationSessionMessageListener.process(ApplicationSessionMessageListener.java:37)
at com.sap.engine.core.cluster.impl6.session.UnorderedChannel$MessageRunner.run(UnorderedChannel.java:71)
at com.sap.engine.core.thread.impl3.ActionObject.run(ActionObject.java:37)
at java.security.AccessController.doPrivileged(Native Method)
at com.sap.engine.core.thread.impl3.SingleThread.execute(SingleThread.java:94)
at com.sap.engine.core.thread.impl3.SingleThread.run(SingleThread.java:162)
Caused by: com.sap.engine.services.applocking.exception.SAPAppLockingIllegalArgumentException: Inconsistency in number of primary keys
at com.sap.engine.services.applocking.TableLockingImpl.getArgument(TableLockingImpl.java:385)
at com.sap.engine.services.applocking.TableLockingImpl.lock(TableLockingImpl.java:128)
at com.sap.engine.services.applocking.TableLockingImpl.lock(TableLockingImpl.java:138)
at com.sap.engine.services.ejb.entity.pm.lock.TableLockingSystem.write(TableLockingSystem.java:82)
at com.sap.engine.services.ejb.entity.pm.PersistentM2M.create(PersistentM2M.java:172)
at com.sap.engine.services.ejb.entity.pm.PersistentCacheM2M.add(PersistentCacheM2M.java:197)
at com.sap.engine.services.ejb.entity.pm.multiple.CollectionM2M.add(CollectionM2M.java:57)
at com.atosorigin.tcc.testing.ejbses.profiling.ProfilerBean.assignSolution(ProfilerBean.java:201)
at com.atosorigin.tcc.testing.ejbses.profiling.ProfilerObjectImpl0.assignSolution(ProfilerObjectImpl0.java:771)
... 32 more
I can't figure out what the problem is with the ORM mapping defined.
On the database level I have three tables. Consultant maps to PFL_CONSULTANT, Solution to PFL_SAPSOLUTIONS. The third table PFL_CONS_SOL_MAP is the help table used for the relationship (having two fields, which are in fact foreign keys from the other two tables to express the assignment of solutions to consultants (where a consultant can have one or more solutions).
ps. : I am running Netweaver Developer Workplace (Netweaver 2004, at stack level 5)
Message was edited by: Theo Paesen
Hm, after disabling 'automatic locking' it works.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
89 | |
10 | |
10 | |
9 | |
6 | |
6 | |
6 | |
5 | |
4 | |
3 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.