-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 
Author Message
 Post subject: How do I map this relationship?
PostPosted: Sun Jun 24, 2007 9:50 am 
Newbie

Joined: Fri Jun 01, 2007 4:52 pm
Posts: 4
I have a system that needs to track people and their roles on various groups and projects. For example a person could be a member on multiple projects and on any given project they could have 1 role. So they could be a member of a project on project a and a lead on project b, c and a member of committee x, y, z.

The db schema that I originally developed used a base person table with a table for projects and a table for committees that held specific information about their role. Something like;

Code:
+--------+         +--------------------+       +---------+
| Person |         | project_member |        | project  |
|----------|         |---------------------|       |-----------|
|pid        |         | pm_id                |        | pro_id   |
|name    |         | pid                     |       | name     |
+---------+        | role                    |       +----------+
                        | pro_id                |
                       +---------------------+


My original design seems to lend itself to a joined-subclass style of inheritance with project_member being a subclass of person. However in testing we've discovered that hibernate does not like it when there is multiple entries on project_member with the same pid. In fact hibernate returns "More than one row with the given identifier was found" in our Junit tests.

After reading the documentation more closely, it turns out that hibernate actually ignores a unique key on a subclass table (pm_id in this case) and only uses the primary key from the parent as the primary key in the child (pid). If my interpretation of the documentation is correct this prevents us from having a joined-subclass style inheritance with multiple entries for the same person.

So my question is; how can we map the relationship as defined in paragraph one of this post? I think that this type of relationship is pretty common so I figure that someone here must be able to throw me bone, so please give me any feedback you have ;)
Code:
Code:


Top
 Profile  
 
 Post subject: Use a many-to-many relationship
PostPosted: Sun Jun 24, 2007 7:30 pm 
Beginner
Beginner

Joined: Thu Jun 21, 2007 9:24 pm
Posts: 20
Location: Lansing, Michigan, USA
More specifically, use a <many-to-many> element with a <composite-element> member for any extra attributes you need.

I think this'll work...


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 25, 2007 7:27 am 
Regular
Regular

Joined: Mon Apr 02, 2007 3:54 am
Posts: 67
Location: Hyderabad
If you will use ecllipse IDE. you will get a auto generated mapping of these 3 table. use middlegen tool.
If you want to do by own. you can also do by many-to one mapping like
<many-to-one name=''some name to refer same as given in query" class="class to which you want to refer" column=''column of same table" property-ref="column of another table to which you want to specify mapping" insert="false" update="false" />
This mapping you need to do according to the flow of data in query.

Thanks,
Gopal
[If helfful, please rate]


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 25, 2007 8:47 am 
Beginner
Beginner

Joined: Mon Apr 23, 2007 8:30 am
Posts: 27
Location: India
Posted by mistake, can't delete. Please Ignore.


Last edited by nikhil78 on Mon Jun 25, 2007 8:52 am, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 25, 2007 8:47 am 
Beginner
Beginner

Joined: Mon Apr 23, 2007 8:30 am
Posts: 27
Location: India
You can also use the http://www.hibernate.org/255.html hibernate tool's reverse enginerring to generate mappings, domain objects and DAO's. This one is pretty neat, helped me a lot :-)

PS: You need the latest JDBC driver for this tool.

Thanks,
Nikhil


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 25, 2007 9:22 am 
Newbie

Joined: Fri Jun 01, 2007 4:52 pm
Posts: 4
Thanks for all your suggestions, I'll start looking into a solution and post back here.

Cheers :)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 26, 2007 4:47 am 
Newbie

Joined: Tue Jun 26, 2007 4:36 am
Posts: 2
Do not use inheritance at all.

The data model you've described seems to let itself to three separate classes:

1) Person with id column "pid"
2) Project with id column "pro_id"
3) ProjectMembership with id column "pm_id"


ProjectMembership has 2 many-to-one properties for Person and Project, plus another property for "role".

Person and Project each contain a many-to-many inverse set relating back to the ProjectMembership class.


A "project member" is not a more specific type for a "person" because a person can be more than just a project member. A "project membership" can have other properties on it such as a start date, end date, pay rate, etc., so you'll be better off by modeling it this way for future expansion.


bart


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 26, 2007 6:53 am 
Beginner
Beginner

Joined: Mon Apr 23, 2007 8:30 am
Posts: 27
Location: India
Another way you can think of designing your tables is as follows:-

Code:
create table Person (
   pid varchar2(10),
   name varchar2(50),
   primary key (pid)
)

create table Project (
   pro_id varchar2(10),
   name varchar2(50),
   primary key (pro_id)
)

create table Project_Member (
   pm_id varchar2(10),
   pid varchar2(10),
   pro_id varchar2(10),
   role varchar2(50),
   primary key (pm_id, pro_id),
   foreign key (pid) references Person,
   foreign key (pro_id) references Project
)


Notice that the primary key in the Project_Member is a composite key comprising of pm_id and pro_id, this will ensure that one member cannot have multiple roles on one project. The primary key will not let this happen as there will always be one and only one entry for a given pm_id and pro_id.

The Hibernate mappings and domain objects for the above design are as follows:-

Hibernate Mappings:-

Person.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="projectmember.Person" table="PERSON">
        <id name="pid" type="string">
            <column name="PID" length="10" />
            <generator class="assigned" />
        </id>
        <property name="name" type="string">
            <column name="NAME" length="50" />
        </property>
        <set name="projectMembers" inverse="true" lazy="true" cascade="all,delete-orphan">
            <key>
                <column name="PID" length="10" />
            </key>
            <one-to-many class="projectmember.ProjectMember" />
        </set>
    </class>
</hibernate-mapping>


Project.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="projectmember.Project" table="PROJECT">
        <id name="proId" type="string">
            <column name="PRO_ID" length="10" />
            <generator class="assigned" />
        </id>
        <property name="name" type="string">
            <column name="NAME" length="50" />
        </property>
        <set name="projectMembers" inverse="true" lazy="true">
            <key>
                <column name="PRO_ID" length="10" not-null="true" />
            </key>
            <one-to-many class="projectmember.ProjectMember" />
        </set>
    </class>
</hibernate-mapping>


ProjectMember.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="projectmember.ProjectMember" table="PROJECT_MEMBER">
        <composite-id name="id" class="projectmember.ProjectMemberId">
            <key-property name="pmId" type="string">
                <column name="PM_ID" length="10" />
            </key-property>
            <key-property name="proId" type="string">
                <column name="PRO_ID" length="10" />
            </key-property>
        </composite-id>
        <many-to-one name="person" class="projectmember.Person" update="true" insert="true" fetch="select">
            <column name="PID" length="10" />
        </many-to-one>
        <many-to-one name="project" class="projectmember.Project" update="false" insert="false" fetch="select">
            <column name="PRO_ID" length="10" not-null="true" />
        </many-to-one>
        <property name="role" type="string">
            <column name="ROLE" length="50" />
        </property>
    </class>
</hibernate-mapping>


Domain Objects:-

Person.java
Code:
package projectmember;

import java.util.HashSet;
import java.util.Set;

public class Person implements java.io.Serializable {

   private static final long serialVersionUID = -6513446322027254027L;

   private String pid;

   private String name;

   private Set projectMembers = new HashSet(0);

   public Person() {
   }

   public Person(String pid) {
      this.pid = pid;
   }

   public Person(String pid, String name, Set projectMembers) {
      this.pid = pid;
      this.name = name;
      this.projectMembers = projectMembers;
   }

   public String getPid() {
      return this.pid;
   }

   public void setPid(String pid) {
      this.pid = pid;
   }

   public String getName() {
      return this.name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public Set getProjectMembers() {
      return this.projectMembers;
   }

   public void setProjectMembers(Set projectMembers) {
      this.projectMembers = projectMembers;
   }

}


Project.java
Code:
package projectmember;

import java.util.HashSet;
import java.util.Set;

public class Project implements java.io.Serializable {

   private static final long serialVersionUID = -5979917496563169126L;

   private String proId;

   private String name;

   private Set projectMembers = new HashSet(0);

   public Project() {
   }

   public Project(String proId) {
      this.proId = proId;
   }

   public Project(String proId, String name, Set projectMembers) {
      this.proId = proId;
      this.name = name;
      this.projectMembers = projectMembers;
   }

   public String getProId() {
      return this.proId;
   }

   public void setProId(String proId) {
      this.proId = proId;
   }

   public String getName() {
      return this.name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public Set getProjectMembers() {
      return this.projectMembers;
   }

   public void setProjectMembers(Set projectMembers) {
      this.projectMembers = projectMembers;
   }

}


ProjectMember.java
Code:
package projectmember;

public class ProjectMember implements java.io.Serializable {

   private static final long serialVersionUID = -4509653258724432914L;

   private ProjectMemberId id;

   private Person person;

   private Project project;

   private String role;
   
   public ProjectMember() {
   }

   public ProjectMember(ProjectMemberId id, Project project) {
      this.id = id;
      this.project = project;
   }

   public ProjectMember(ProjectMemberId id, Person person, Project project, String role) {
      this.id = id;
      this.person = person;
      this.project = project;
      this.role = role;
   }

   public ProjectMemberId getId() {
      return this.id;
   }

   public void setId(ProjectMemberId id) {
      this.id = id;
   }

   public Person getPerson() {
      return this.person;
   }

   public void setPerson(Person person) {
      this.person = person;
   }

   public Project getProject() {
      return this.project;
   }

   public void setProject(Project project) {
      this.project = project;
   }

   public String getRole() {
      return role;
   }

   public void setRole(String role) {
      this.role = role;
   }

}


And finally the ID class:-
Code:
package projectmember;

public class ProjectMemberId implements java.io.Serializable {

   private static final long serialVersionUID = -2957054540624377023L;

   private String pmId;

   private String proId;

   public ProjectMemberId() {
   }

   public ProjectMemberId(String pmId, String proId) {
      this.pmId = pmId;
      this.proId = proId;
   }

   public String getPmId() {
      return this.pmId;
   }

   public void setPmId(String pmId) {
      this.pmId = pmId;
   }

   public String getProId() {
      return this.proId;
   }

   public void setProId(String proId) {
      this.proId = proId;
   }

   public boolean equals(Object other) {
      if ((this == other))
         return true;
      if ((other == null))
         return false;
      if (!(other instanceof ProjectMemberId))
         return false;
      ProjectMemberId castOther = (ProjectMemberId) other;

      return ((this.getPmId() == castOther.getPmId()) || (this.getPmId() != null
            && castOther.getPmId() != null && this.getPmId().equals(
            castOther.getPmId())))
            && ((this.getProId() == castOther.getProId()) || (this
                  .getProId() != null
                  && castOther.getProId() != null && this.getProId()
                  .equals(castOther.getProId())));
   }

   public int hashCode() {
      int result = 17;

      result = 37 * result
            + (getPmId() == null ? 0 : this.getPmId().hashCode());
      result = 37 * result
            + (getProId() == null ? 0 : this.getProId().hashCode());
      return result;
   }

   public String toString() {
      StringBuffer buffer = new StringBuffer();
      buffer.append(getPmId() + "." + getProId());
      return buffer.toString();
   }
}


Hope this help, if it does don't forget to rate :-)

Thanks,
Nikhil


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.