Results 1 to 4 of 4

Thread: Need Help - Many-to-many and Spring transaction mgmt

  1. #1
    Join Date
    Nov 2004
    Posts
    159

    Default Need Help - Many-to-many and Spring transaction mgmt

    Hello everyone,

    I've class Project which has many-to-many relation with class Resource; Hence i introduced an association class ProjectResource which has the composite id and other attributes.

    I've a projectDAO class which provides, among other methods, insertProject. resourceDAO has, among other methods, insertResource. I need a way to added project, resource and related projectresource all in one txn. This way, if one insert fails, everything else should fail.

    In my business interface iRMTFacade, i added a method called 'addProjectAndResource' as follows:

    Code:
     void addProjectAndResource(Project project, Resource resource);
    Implementation for this is as follows:

    Code:
    	 	public void addProjectAndResource(Project project, Resource resource) {
    	 		this.projectDao.insertProject(project);
    			this.resourceDao.insertResource(resource);
    	 	}
    As the ProjectResource class has a composite id (please see the code for constructor of this class below) of projectId and resourceId, i need to first insert project and resource entries.

    Code:
    public ProjectResource(ProjectResource prjres) {
    //		ProjectResource(prjres.getUsername(), prjres.getStartDate(), prjres.getAssignmentDate(), prjres.getProject(),
    //							prjres.getResource());
    		
    		this.username = prjres.getUsername();
    		this.startDate = prjres.getStartDate();
    		this.assignmentDate = prjres.getAssignmentDate();
    		
    		this.project = prjres.getProject();
    		this.resource = prjres.getResource();
    		
    		this.id.projectId = this.project.getId();
    		this.id.resourceId = this.resource.getId();
    		
    		project.getProjectResources().add(this);
    		resource.getProjectResources().add(this);
    	}
    This ProjectResource class has a composite id whic has two properties projectId, resourceId and the getter/setter methods for it.

    Now the PROBLEM is that, first i need to insert Project, then Resource into the datastore. Then, logically speaking, if i JUST create a new ProjectResource object, Hibernate should automatically create an entry for this in the ProjectResource TAble.

    I wrote a JUnit test code as follows:


    Code:
    	public void testInsertProjectAndResource() {
    		Collection projects = rmt.findProjects("eApproval");
    		int found = projects.size();
    		
    		assertTrue(found == 0);
    		
    		Collection resources = rmt.findResources("Raghu");
    		int res_found = resources.size();
    		
    		assertTrue(found == 0);
           	rmt.addProjectAndResource(project2, resource2);
    		
    		ProjectResource prjres = new ProjectResource("Raghu", new Date(), new Date(), project2, resource2);
    		rmt.insertProjectResource( prjres);
    		
    		assertTrue(!project2.isNew());
    
    		projects = rmt.findProject(project2);
    		assertEquals(found + 1, projects.size());
    		
    		resources = rmt.findResource(resource2);
    		assertEquals(res_found + 1, resources.size());
    		
    	}

    BUT I DON'T SEE ANY ENTRY IN THE ProjectResource table when run the above junit test. Why? Could someone let me know what's that i'm missing.


    Also, as per Spring IoC, i'm not supposed to created any object in my code and the autowiring should happen through spring config file. Does it mean that i need to add the configuration to create new ProjectResource object in the Spring config file itself? If yes, how do i do that?


    I greatly appreciate any input in this.

    Thanks!

  2. #2

    Default

    Hi spring04,

    You don't need to create a mapping file or POJO for the association table. Hibernate will do the work of creating the necessary CRUD SQL if you setup your mapping files properly. And, of course, Spring will manage the transaction for you with a properly configured applicationContext.xml. Give this a try....

    Project mapping file:
    Code:
    <hibernate-mapping package="domain">
    
        <class name="Project" table="PROJECT">
            <id name="id" column="id" type="java.lang.Long">
                <generator class="native"/>
            </id>
      				<!-- Properties -->
    .
    .
    .
    
      				<!-- Associations -->
            <!-- Bi-directional -->
            <set name="resources" table="PROJECT_RESOURCE" cascade="all">
            	<key column="PROJECT_ID"/>
            	<many-to-many column="RESOURCE_ID" class="Resource"/>
            </set>
        </class>
    </hibernate-mapping>
    Resource mapping file:
    Code:
    <hibernate-mapping package="domain">
    
        <class name="Resource" table="RESOURCE">
            <id name="id" column="id" type="java.lang.Long">
                <generator class="native"/>
            </id>
      				<!-- Properties -->
    .
    .
    .
    
      				<!-- Associations -->
            <!-- Bi-directional -->
            <set name="projects" table="PROJECT_RESOURCE" cascade="all">
            	<key column="RESOURCE_ID"/>
            	<many-to-many column="PROJECT_ID" class="Project"/>
            </set>
        </class>
    </hibernate-mapping>
    In your Project DAO you would have code like this:
    Code:
      public void save&#40;Project project&#41; throws DataAccessException &#123;
        Long id = project.getId&#40;&#41;;
        
        if &#40;id != null && id.longValue&#40;&#41; > 0&#41;
          getHibernateTemplate&#40;&#41;.update&#40;project&#41;;
        
        else
          getHibernateTemplate&#40;&#41;.save&#40;project&#41;;
      &#125;
    
      public void delete&#40;Project project&#41; throws DataAccessException &#123;
    		getHibernateTemplate&#40;&#41;.delete&#40;project&#41;;
      &#125;
    And do something likewise in the Resource DAO.

    Put the SQL and association burden on Hibernate and the transaction burden on Spring. They can handle it. :wink:

    HTH,

  3. #3
    Join Date
    Nov 2004
    Posts
    159

    Default

    Thanks ticklishturtletoe.

    What will you do if you have some extra attributes to maintain in the association table???

    Thanks!

  4. #4

    Default

    I try to avoid that situation as much as possible. But on the occasions when the association table must have fields other than foreign keys, I do need to create a mapping file and POJO for it as you've done for your ProjectResource table.

    But your iRMTFacade implementation would have a function like this:
    Code:
    public void addProjectResource&#40;ProjectResource projectResource&#41; &#123; 
              this.projectDao.insertProject&#40;projectResource&#41;; 
           &#125;
    And your test code could be re-written like this:
    Code:
    Project project = new Project&#40;/* set property values */&#41;;
    Resource resource = new Resource&#40;/* set property values */&#41;;
    ProjectResource projRes = new ProjectResource&#40;/* set property values */&#41;;
    
    projRes.setProject&#40;project&#41;;
    projRes.setResource&#40;resource&#41;;
    
    rmt.addProjectResource&#40;projRes&#41;;
    Once again, the burden of the association is borne by Hibernate, which relies on correct mapping file setup to get it right.

    HTH,

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •