Hi,

I have an application that works with objects, that are linked in many ways among each other.
What is the best way to save them?
I try to to it by long transactions, because the Objects are used while the whole application
and and i don't want to hold one transaction all the time to hold them persistent.
Its a multi-user web-application and i can't be sure, that the conection will be closed correctly.
So i just open a connection, when some objects have to be read/saved/updated and want to
save them by long transactions. When i do this:

db.setAutoStore(false);
db.begin();
db.update(myObject);
db.commit();

i get the error:

Commit failed: org.exolab.castor.jdo.TransactionAbortedException: Nested error:
org.exolab.castor.jdo.PersistenceException: Object, com.sourcepark.ticketsystem.Ticket@305236,
links to another object, com.sourcepark.ticketsystem.Priority@6a0105 that is not
loaded/updated/created in this transaction

If i set db.setAutoStore(true) i get the error:

Error while saving object: org.exolab.castor.jdo.DuplicateIdentityException: update object
which is already in the transaction

because i use some objects in many ways, i.e. the object 'state' can be a pre-state and a
successor-state for another object and there are many other relations like this. I've tried
to set the affected objects to access="read-only" in mapping.xml but without success.

In the JDO-FAQ is written, that castor only supports bi-directional relationships, does
that mean, if object1 contains a reference to object2, object2 should contain a vector
of object1's?

I expanded my mapping.xml, but now castor works very slowly, when i load a single
user, the whole datamodel is loaded from DB cause all objects are linked among each other.
Is it usefull to use castor for a web-application with complex datamodel? Whats about
performance when there are many users and large databases. Could lazy-loading solve this
problem?

I've appended the whole mapping.xml for getting an impression about the object-structute.
My main question is, if it's advisable to use castor for a multi-user web-application with
such a datamodel and if yes, what is the most performance-friendly approach to save and
load the objects.

Thanks in advance,
Steffen
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Object Mapping DTD Version 1.0//EN"
                         "http://castor.exolab.org/mapping.dtd";>

<mapping>

<!--/////////////////// Mapping for Person //////////////////////////-->

  <class name="com.sourcepark.access.Person" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="PERSON" xml="person" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
    
    <field name="firstName"  type="string">
      <sql name="FIRST_NAME" type="char" dirty="check" />
      <xml node="text" />
    </field>   
    
    <field name="lastName"  type="string">
      <sql name="LAST_NAME" type="char" dirty="check" />
      <xml node="text" />
    </field>   
  <field name="users" type="com.sourcepark.access.User" collection="vector"
                    set-method="setUsersAsReference" get-method="getUsersAsReference">
     <sql many-key="PERSON_ID"/>
  </field>    
    
   </class>


<!--/////////////////// Mapping for User ////////////////////////////-->
  <class name="com.sourcepark.access.User" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="USERS"/>
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
    </field>
    
    <field name="person"  type="com.sourcepark.access.Person" required="true">
      <sql name="PERSON_ID"/>
    </field>  
    
    <field name="name" type="string">
      <sql name="NAME" type="char" required="true"/>
    </field>   
    
    <field name="password" type="string">
      <sql name="PASSWORD" type="char"  required="true"/>
    </field>   

  <field name="roles" type="com.sourcepark.workflows.Role" collection="vector"
                    set-method="setRolesAsReference" get-method="getRolesAsReference">
     <sql name="ROLE" many-table="ROLES_USERS" many-key="USERS" />
  </field>    
  
  <field name="userGroups" type="com.sourcepark.access.UserGroup" collection="vector"
                    set-method="setUserGroupsAsReference" get-method="getUserGroupsAsReference">
     <sql name="USERGROUP" many-table="USER_TO_USERGROUPS" many-key="USERID" />
  </field>    

  <field name="events" type="com.sourcepark.ticketsystem.Event" collection="vector"
                    set-method="setEventsAsReference" get-method="getEventsAsReference">
     <sql many-key="USER_ID"/>
  </field>    
  <field name="recipientTickets" type="com.sourcepark.ticketsystem.Ticket" collection="vector"
                    set-method="setRecipientTicketsAsReference" get-method="getRecipientTicketsAsReference">
     <sql many-key="RECIPIENT"/>
  </field>    
  <field name="transactorTickets" type="com.sourcepark.ticketsystem.Ticket" collection="vector"
                    set-method="setTransactorTicketsAsReference" get-method="getTransactorTicketsAsReference">
     <sql many-key="TRANSACTOR"/>
  </field>    
</class>  

<!--/////////////////// Mapping for UserGroup //////////////////////-->

  <class name="com.sourcepark.access.UserGroup" identity="id"  key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="USERGROUPS" xml="userGroups" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
    
    <field name="name" type="string">
      <sql name="NAME" type="char" dirty="check" />
      <xml node="text" />
    </field>   

    <field name="users" type="com.sourcepark.access.User" collection="vector"
                    set-method="setUsersAsReference" get-method="getUsersAsReference">
     <sql name="USERID" many-table="USER_TO_USERGROUPS" many-key="USERGROUP" />
    </field>    
  
   </class>  

<!--/////////////////// Mapping for Project ////////////////////////-->

  <class name="com.sourcepark.projects.Project" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="PROJECTS" xml="projects" />

    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
    
  <!--________________NAME______________________-->   
    <field name="name" type="string">
      <sql name="NAME" type="char" dirty="check" />
      <xml node="text" />
    </field>   
    
  <!--________________SUPER_PROJECT________________________-->
    <field name="superProjects" type="com.sourcepark.projects.Project" collection="vector"
                    set-method="setSuperProjectsAsReference" get-method="getSuperProjectsAsReference">
     <sql name="SUPERPROJECT_ID" many-table="PROJECT_SUPERPROJECT" many-key="PROJECT_ID" />
  </field>    

   <field name="tickets" type="com.sourcepark.ticketsystem.Ticket" collection="vector"
                    set-method="setTicketsAsReference" get-method="getTicketsAsReference">
     <sql many-key="PROJECT"/>
  </field>    
</class>

<!--/////////////////// Mapping for Ticket///////////////////////////-->
  
  <class name="com.sourcepark.ticketsystem.Ticket" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="TICKET" xml="ticket" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
    
    <field name="name" type="string">
      <sql name="NAME" type="char"/>
      <xml node="text" />
    </field>
    
     <field name="priority" type="com.sourcepark.ticketsystem.Priority">
       <sql name="PRIORITY"/>
     </field> 
   
     <field name="type" type="com.sourcepark.ticketsystem.Type">
       <sql name="TYPE" read-only="true" dirty="ignore"/>
     </field>  
  
     <field name="recipient" type="com.sourcepark.access.User">
       <sql name="RECIPIENT"/>
     </field>    

     <field name="recipientType"      type="integer">      
     <sql name="RECIPIENT_TYPE" type="integer"/>
     </field>    
     
     <field name="state" type="com.sourcepark.workflows.State">
       <sql name="STATE"/>
     </field>      
     
     <field name="project" type="com.sourcepark.projects.Project">
       <sql name="PROJECT"/>
     </field>      
		 
     <field name="transactor" type="com.sourcepark.access.User">
       <sql name="TRANSACTOR"/>
     </field>	

     <field name="workflow" type="com.sourcepark.workflows.Workflow">
       <sql name="WORKFLOW"/>
     </field>		
		 	 	 
    <field name="deadline" type="string">
      <sql name="DEADLINE" type="char"/>
    </field> 		 

     <field name="description" type="string">
       <sql name="DESCRIPTION" type="char"/>
     </field>  

  <field name="events" type="com.sourcepark.ticketsystem.Event" collection="vector"
                    set-method="setEventsAsReference" get-method="getEventsAsReference">
     <sql many-key="TICKET_ID"/>
  </field>    
       
</class>

<!--/////////////////// Mapping for Event ///////////////////////////-->

  <class name="com.sourcepark.ticketsystem.Event" depends="com.sourcepark.ticketsystem.Ticket" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="EVENTS" xml="events" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="numeric"/><!--type="integer"-->
    </field>
    
    <field name="ticket"  type="com.sourcepark.ticketsystem.Ticket" >
      <sql name="TICKET_ID"/>
    </field>
  
    <field name="user"  type="com.sourcepark.access.User" >
      <sql name="USER_ID"/>
    </field>
  
    <field name="day" type="string">
      <sql name="DAY" type="char" dirty="check" />
    </field>   

    <field name="state" type="com.sourcepark.workflows.State" >
      <sql name="STATE" read-only="true" dirty="ignore"/>
    </field>
  
   </class>

<!--/////////////////// Mapping for Type ////////////////////////-->

  <class name="com.sourcepark.ticketsystem.Type" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="TYPES" xml="type" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
		
    <field name="name" type="string">
      <sql name="NAME" type="char" dirty="check" />
      <xml node="text" />
    </field>  		

    <field name="workflow" type="com.sourcepark.workflows.Workflow" >
      <sql name="WORKFLOW"/>
    </field>    
    
  <field name="tickets" type="com.sourcepark.ticketsystem.Ticket" collection="vector"
                    set-method="setTicketsAsReference" get-method="getTicketsAsReference">
     <sql many-key="TYPE"/>
  </field>    
</class>

<!--/////////////////// Mapping for PRIORITY ////////////////////////-->

  <class name="com.sourcepark.ticketsystem.Priority" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="PRIORITIES" xml="priority" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
		
    <field name="name" type="string">
      <sql name="NAME" type="char" dirty="check" />
      <xml node="text" />
    </field>  		
 
    <field name="workflow" type="com.sourcepark.workflows.Workflow" >
      <sql name="WORKFLOW"/>
      <xml node="attribute"/>
    </field> 
    
  <field name="tickets" type="com.sourcepark.ticketsystem.Ticket" collection="vector"
                    set-method="setTicketsAsReference" get-method="getTicketsAsReference">
     <sql many-key="PRIORITY"/>
  </field>    
         
	</class>

<!--/////////////////// Mapping for Workflow /////////////////////////-->

  <class name="com.sourcepark.workflows.Workflow" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="WORKFLOWS" xml="workflows" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
		
    <field name="name" type="string">
      <sql name="NAME" type="char" dirty="check" />
      <xml node="text" />
    </field>   		

  <field name="states" type="com.sourcepark.workflows.State" collection="vector"
                    set-method="setStatesAsReference" get-method="getStatesAsReference">
     <sql many-key="WORKFLOW"   read-only="true" dirty="ignore"/>
  </field>    

  <field name="sequences" type="com.sourcepark.workflows.Sequence" collection="vector"
                    set-method="setSequencesAsReference" get-method="getSequencesAsReference">
     <sql many-key="WORKFLOW"  read-only="true"/>
  </field>    

  <field name="roles" type="com.sourcepark.workflows.Role" collection="vector"
                    set-method="setRolesAsReference" get-method="getRolesAsReference">
     <sql name="ROLE" many-table="ROLES_WORKFLOW" many-key="WORKFLOW" />
  </field>    
  
  <field name="types" type="com.sourcepark.ticketsystem.Type" collection="vector"
                    set-method="setTypesAsReference" get-method="getTypesAsReference">
     <sql many-key="WORKFLOW"  read-only="true"/>
  </field>    
  
  <field name="tickets" type="com.sourcepark.ticketsystem.Ticket" collection="vector"
                    set-method="setTicketsAsReference" get-method="getTicketsAsReference">
     <sql many-key="WORKFLOW"/>
  </field>    
  
  <field name="actions" type="com.sourcepark.workflows.Action" collection="vector"
                    set-method="setActionsAsReference" get-method="getActionsAsReference">
     <sql many-key="WORKFLOW"/>
  </field>    
  
  <field name="priorities" type="com.sourcepark.ticketsystem.Priority" collection="vector"
                    set-method="setPrioritiesAsReference" get-method="getPrioritiesAsReference">
     <sql many-key="WORKFLOW"/>
  </field>    
</class>


<!--/////////////////// Mapping for Role /////////////////////////////-->

  <class name="com.sourcepark.workflows.Role" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="ROLES" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
    </field>
		
    <field name="name" type="string">
      <sql name="NAME" type="char" dirty="check" />
    </field>		
    
  <field name="users" type="com.sourcepark.access.User" collection="vector"
                    set-method="setUsersAsReference" get-method="getUsersAsReference">
     <sql name="USERS" many-table="ROLES_USERS" many-key="ROLE" />
  </field>  
  
  <field name="workflows" type="com.sourcepark.workflows.Workflow" collection="vector"
                    set-method="setWorkflowsAsReference" get-method="getWorkflowsAsReference">
     <sql name="WORKFLOW" many-table="ROLES_WORKFLOW" many-key="ROLE" />
  </field>    
  
  <field name="preStates" type="com.sourcepark.workflows.State" collection="vector"
                    set-method="setPreStatesAsReference" get-method="getPreStatesAsReference">
     <sql name="PRE_STATE" many-table="ROLES_PRE_STATES" many-key="ROLE"  read-only="true" dirty="ignore"/>
  </field>    
  
  <field name="sucStates" type="com.sourcepark.workflows.State" collection="vector"
                    set-method="setSucStatesAsReference" get-method="getSucStatesAsReference">
     <sql name="SUC_STATE" many-table="ROLES_SUC_STATES" many-key="ROLE" read-only="true" dirty="ignore" />
  </field>    
  
  <field name="recievedStates" type="com.sourcepark.workflows.State" collection="vector"
                    set-method="setRecievedStatesAsReference" get-method="getRecievedStatesAsReference">
     <sql name="STATE" many-table="SELECT_RECIPIENTS" many-key="ROLE"  read-only="true" dirty="ignore"/>
  </field>    
  
  <field name="actions" type="com.sourcepark.workflows.Action" collection="vector"
                    set-method="setActionsAsReference" get-method="getActionsAsReference">
     <sql name="ACTION_ID" many-table="ACTIONS_ROLES" many-key="ROLE_ID" />
  </field>    
</class> 

<!--/////////////////// Mapping for State /////////////////////////////-->
  <class name="com.sourcepark.workflows.State" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="STATES" xml="states" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
		
    <field name="name" type="string">
      <sql name="NAME" type="char" dirty="check" />
      <xml node="text" />
    </field>

    <field name="workflow" type="com.sourcepark.workflows.Workflow" >
      <sql name="WORKFLOW"/>
    </field>
    
  <field name="rolesForThisPreState" type="com.sourcepark.workflows.Role" collection="vector"
                    set-method="setRolesForThisPreStateAsReference" get-method="getRolesForThisPreStateAsReference">
     <sql name="ROLE" many-table="ROLES_PRE_STATES" many-key="PRE_STATE"  read-only="true" dirty="ignore"/>
  </field>    
  
  <field name="rolesForThisSucState" type="com.sourcepark.workflows.Role" collection="vector"
                    set-method="setRolesForThisSucStateAsReference" get-method="getRolesForThisSucStateAsReference">
     <sql name="ROLE" many-table="ROLES_SUC_STATES" many-key="SUC_STATE" read-only="true" dirty="ignore" />
  </field>    
  
  <field name="recipientRoles" type="com.sourcepark.workflows.Role" collection="vector"
                    set-method="setRecipientRolesAsReference" get-method="getRecipientRolesAsReference">
     <sql name="ROLE" many-table="SELECT_RECIPIENTS" many-key="STATE" read-only="true" dirty="ignore" />
  </field>    
  
  <field name="tickets" type="com.sourcepark.ticketsystem.Ticket" collection="vector"
                    set-method="setTicketsAsReference" get-method="getTicketsAsReference">
     <sql many-key="STATE"/>
  </field>    
  
  <field name="preStateSequences" type="com.sourcepark.workflows.Sequence" collection="vector"
                    set-method="setPreStateSequencesAsReference" get-method="getPreStateSequencesAsReference">
     <sql many-key="PRE_STATE"/>
  </field>    
  
  <field name="sucStateSequences" type="com.sourcepark.workflows.Sequence" collection="vector"
                    set-method="setSucStateSequencesAsReference" get-method="getSucStateSequencesAsReference">
     <sql many-key="SUC_STATE"/>
  </field>    
  
  <field name="events" type="com.sourcepark.ticketsystem.Event" collection="vector"
                    set-method="setEventsAsReference" get-method="getEventsAsReference">
     <sql many-key="STATE"/>
  </field>    
</class> 

<!--/////////////////// Mapping for Sequence //////////////////////////-->

  <class name="com.sourcepark.workflows.Sequence" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="SEQUENCE" xml="sequence" />

    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
		    
    <field name="preState"  type="com.sourcepark.workflows.State" >
      <sql name="PRE_STATE" read-only="true" dirty="ignore"/>
    </field>
		    
    <field name="sucState"  type="com.sourcepark.workflows.State" >
      <sql name="SUC_STATE" read-only="true" dirty="ignore"/>
    </field>
		
    <field name="workflow" type="com.sourcepark.workflows.Workflow" >
      <sql name="WORKFLOW"/>
    </field>
    
    <field name="ranking"  type="integer" >
      <sql name="RANKING" type="integer"/>
      <xml node="attribute"/>
    </field>
		  
   </class> 

<!--/////////////////// Mapping for Action /////////////////////////////-->

  <class name="com.sourcepark.workflows.Action" identity="id" key-generator="MAX">
    <cache-type type="unlimited"/>
    <map-to table="ACTIONS" xml="actions" />
    
    <field name="id" type="integer" >
      <sql name="ID" type="integer"/>
      <xml node="attribute"/>
    </field>
		
    <field name="name" type="string">
      <sql name="NAME" type="char" dirty="check" />
      <xml node="text" />
    </field>			
		 
    <field name="workflow" type="com.sourcepark.workflows.Workflow" >
      <sql name="WORKFLOW"/>
    </field>
    
  <field name="roles" type="com.sourcepark.workflows.Role" collection="vector"
                    set-method="setRolesAsReference" get-method="getRolesAsReference">
     <sql name="ROLE_ID" many-table="ACTIONS_ROLES" many-key="ACTION_ID" />
  </field>    
    
</class>
			
</mapping>

Reply via email to