Container Managed Relationships in a many-to-many (n-n) context.

In this example, the Course CMP bean is related to the Student CMP bean. Since one student can take several different courses, and one course can be taught to several different students, this is a many-to-many relation.

We can have Resin-CMP manage this relationship for us so that we don't have to use JDBC to find related entities. Our two beans in this example will use the following 3 tables:

    # this table stores the course entities
    CREATE TABLE many2many_courses (
      name VARCHAR(250) NOT NULL,
      instructor VARCHAR(250),

      PRIMARY KEY(name)
    );

    # this table stores the student entities
    CREATE TABLE many2many_students (
      name VARCHAR(250) NOT NULL,

      PRIMARY KEY(name)
    );

    # this table is used by Resin-CMP to maintain the relationships between
    # students and courses
    DROP TABLE many2many_student_course_mapping;
    CREATE TABLE many2many_student_course_mapping (
      many2many_students VARCHAR(250) NOT NULL,
      many2many_courses VARCHAR(250) NOT NULL
    );
    

In addition to one table each for the two entities, we need a mapping table. It is called it many2many_student_course_mapping as defined in the deployment descriptor. Resin-CMP uses the mapping table to keep track of which students are related to which courses.
The two entries in this table are the primary key of the student and the course entity, respectively. The names of the two fields in the mapping table need to match the names of the two CMP Beans that participate in this relation.
Note that only a many2many relation needs a mapping table -- one2one and one2many relations can make do with the two entity tables because at least one entity involved has a multiplicity of one.

Setting up the deployment descriptor

All setup related to CMR is done in the <relationships> section. We set up our many2many relationship like this:

 <relationships>
  <ejb-relation>
   <ejb-relation-name>many2many_student_course_mapping</ejb-relation-name>
   <ejb-relationship-role>
    <multiplicity>Many</multiplicity>
    <relationship-role-source>
     <ejb-name>many2many_StudentBean</ejb-name>
    </relationship-role-source>
    <cmr-field>
     <cmr-field-name>courseList</cmr-field-name>
     <cmr-field-type>java.util.Collection</cmr-field-type>
    </cmr-field>
   </ejb-relationship-role>
   <ejb-relationship-role>
    <multiplicity>Many</multiplicity>
    <relationship-role-source>
     <ejb-name>many2many_CourseBean</ejb-name>
    </relationship-role-source>
    <cmr-field>
     <cmr-field-name>studentList</cmr-field-name>
     <cmr-field-type>java.util.Collection</cmr-field-type>
    </cmr-field>
   </ejb-relationship-role>
  </ejb-relation>
 </relationships>

Every <ejb-relation> has two participating entity beans. Their role in the relation is defined within a <ejb-relationship-role> section. Use the <ejb-name> tag to describe which entity the <ejb-relationship-role> block belongs to.

Resin-CMP expects the mapping table to have the same name as the relation it is used for. We can set the relation's name with the <ejb-relation-name> tag. In this case, the relation is called many2many_student_course_mapping, which is why we also have a table called many2many_student_course_mapping in our schema.

Writing code for the CMR fields

For the CourseBean, we have defined studentList as a CMR field. We need to match this with a method declaration in CourseBean.java:


    abstract public Collection getStudentList();
    

which Resin-CMP will implement for us. The getStudentList() method will return a Collection of all students enrolled in a course. For adding Students to the course, instead of defining a set-method, we can simply add to the Collection:


      // adding a student to a house
      house.getStudentList().add(student);
    

We have the reverse case with StudentBean's courseList CMR field. In StudentBean.java, we need to define


    abstract public Collection getCourseList();
    
Resin-CMP will implement this method to return a Collection of all Courses that a student is currently enrolled in. To enroll the student in another Course, we can call

      // enrolling a student in a course
      student.getCourseList().add(course);