How to set up many to many relationship in hibernate using XML mapping

5k Views Asked by At

I have the following situation:

I am new to hibernate and I have a project to complete within the next days.

It is about a CRUD Web application in Java.The first steps have completed but I am really stuck and I cannot find any help in internet about the following situation:

i have an a Project Table which can have many Actions from Action table. ( many-to- many Relationship).

I also have a Payments table which has a primary key,( paymentId) and the 2 foreign keys of Project and action ( projectId,actionId) and also some other fields like paymentMethod, price, startDate, endDate. I actually use Payments table to connect each project to each action adding some additional information like amount, etc..

I hope i clarify my thoughts about the general view.

I don't know how i have to do the mapping files? Do i have to create 2 mapping files or 3? (Project.hbm.xml , action.hbm.xml and payments.hbm.xml)

In the beginning i thought to do split the relationship into the following:

a project POJO class to have one to many relationship with payments ( and the mapping XML will the as having 1 relationship one to many) and the action POJO class to have many-to-one with payments ( also with the relevant XML mapping file).

And also have a POJO class with payments, including Objects Action and Projects, and the relevant one to many relationships in XML files.

I have not seen such an implementation to any tutorial neither to any site i don't know if that is ok ?

The only thing i found was Many-to-many relationship using annotation ( mainly) and having the mid-step table ( payments in my case ) with only the 2 foreign keys without any primary key and extra fields like these that i want.

project XML:

 <?xml version="1.0" encoding="UTF-8"?>

    <!DOCTYPE hibernate-mapping PUBLIC
     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

      <hibernate-mapping>
      <class name="com.nisid.entities.Project" table="projects">
      <meta attribute="class-description"> This class contains the project records. </meta> 
       <id name="projectId" type="int" column="projectId"> 
        <generator class="native">

        </generator> 
    </id> 

    <many-to-one name="fkCustomer" class="com.nisid.entities.Customers"
            fetch="select">
            <column name="customerId" not-null="true"/>
    </many-to-one>
      <set name="payments"  
            lazy="true" fetch="select" cascade="all">
          <key>
                <column name="projectId" />
            </key>


            <one-to-many class="com.nisid.entities.Payment" />
        </set>
 <property name="projectName" column="projectName" type="string"/> 
    <property name="projectDescription" column="description" type="string"/> 
   </class>
    </hibernate-mapping>

Action xml:

<?xml version="1.0" encoding="UTF-8"?>

        <!DOCTYPE hibernate-mapping PUBLIC
          "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

        <hibernate-mapping>
            <class name="com.nisid.entities.Action" table="actions" >
                <id name="actionId" type="int">
                    <column name="actionId" />
                    <generator class="native" >
                     </generator> 
                </id>
                <property name="actionName" type="string">
                    <column name="actionName"   />
                </property>

                <set name="payments" inverse="true" lazy="true" fetch="select">
                    <key>
                        <column name="actionId" />
                    </key>
                    <one-to-many class="com.nisid.entities.Payment" />
                </set>

            </class>
        </hibernate-mapping>

Payment ( mapping xml):

<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
      "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

    <hibernate-mapping>
        <class name="com.nisid.entities.Payment" table="payments">


            <composite-id name="paymentId" class="com.nisid.entities.PaymentID" >

                <key-property name="myproject" column="projectId" />
                <key-property name="myaction" column="actionId" />

            </composite-id>

            <component name="myproject">

                <many-to-one name="project" class="com.nisid.entities.Project"
                    >
                    <column name="projectId" not-null="true" />
                </many-to-one>

            </component>

            <component name="myaction">

                <many-to-one name="action" class="com.nisid.entities.Action"
                    >
                    <column name="actionId" not-null="true" />
                </many-to-one>

            </component>


            <property name="amount" column="amount" type="int"/> 
            <property name="paymentDate" column="paymentDate" type="date"/> 
            <property name="paymentExpire" column="paymentExpire" type="date"/> 
            <property name="paymentMethod" column="paymentMethod" type="string"/>

        </class>

And ppojo classes:

Action:

/*
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package com.nisid.entities;

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

    /**
     *
     * @author p293
     */
    public class Action {

        private int actionId;
        private String actionName;
         private Set payments=new HashSet();



        public Action(){}

        public Action(String actionName) {
            this.actionName = actionName;
        }

        public int getActionId() {
            return actionId;
        }

        public void setActionId(int actionId) {
            this.actionId = actionId;
        }



        public String getActionName() {
            return actionName;
        }

        public void setActionName(String actionName) {
            this.actionName = actionName;
        }

        public Set getPayments() {
            return payments;
        }

        public void setPayments(Set payments) {
            this.payments = payments;
        }



        @Override
        public int hashCode() {
            int hash = 5;
            hash = 89 * hash + Objects.hashCode(this.actionName);
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Action other = (Action) obj;
            if (!Objects.equals(this.actionName, other.actionName)) {
                return false;
            }
            return true;
        }





        @Override
        public String toString() {
            return "Action{" + "=" + actionName + '}';
        }



    }

Project:

/*
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package com.nisid.entities;

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

    /**
     *
     * @author p293
     */
    public class Project {

        private int projectId;
        private String projectName;
        private String projectDescription;
        private Customers fkCustomer;
        private Set payments=new HashSet();

        public Project(){


        }

        public Project( String projectName, String projectDescription) {

            this.projectName = projectName;
            this.projectDescription = projectDescription;
        }


        public int getProjectId() {
            return projectId;
        }

        public void setProjectId(int projectId) {
            this.projectId = projectId;
        }

        public String getProjectName() {
            return projectName;
        }

        public void setProjectName(String projectName) {
            this.projectName = projectName;
        }

        public String getProjectDescription() {
            return projectDescription;
        }

        public void setProjectDescription(String projectDescription) {
            this.projectDescription = projectDescription;
        }

        public Customers getFkCustomer() {
            return fkCustomer;
        }

        public void setFkCustomer(Customers fkCustomer) {
            this.fkCustomer = fkCustomer;
        }

        public Set getPayments() {
            return payments;
        }

        public void setPayments(Set payments) {
            this.payments = payments;
        }








        @Override
        public int hashCode() {
            int hash = 7;
            hash = 79 * hash + Objects.hashCode(this.projectName);
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Project other = (Project) obj;
            if (!Objects.equals(this.projectName, other.projectName)) {
                return false;
            }
            return true;
        }


         @Override
        public String toString() {
            return "Project{" + "projectName=" + projectName + ",with description="    +       projectDescription + '}';
        }



    }

Payment:

/*
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package com.nisid.entities;

    import java.util.Date;
    import java.util.HashSet;
    import java.util.Objects;
    import java.util.Set;

    /**
     *
     * @author p293
     */
    public class Payment {

        private PaymentID paymentId=new PaymentID();
        private int amount;
        private Date paymentDate;
        private Date paymentExpire;
        private String paymentMethod;



        public Payment(int fkProjectId, int fkActionId, int amount, Date paymentDate, Date paymentExpire, String paymentMethod) {

            this.amount = amount;
            this.paymentDate = paymentDate;
            this.paymentExpire = paymentExpire;
            this.paymentMethod=paymentMethod;

        }

        public Payment(){}

        public PaymentID getPaymentId() {
            return paymentId;
        }

        public void setPaymentId(PaymentID paymentId) {
            this.paymentId = paymentId;
        }

        public int getAmount() {
            return amount;
        }

        public void setAmount(int amount) {
            this.amount = amount;
        }

        public Date getPaymentDate() {
            return paymentDate;
        }

        public void setPaymentDate(Date paymentDate) {
            this.paymentDate = paymentDate;
        }

        public Date getPaymentExpire() {
            return paymentExpire;
        }

        public void setPaymentExpire(Date paymentExpire) {
            this.paymentExpire = paymentExpire;
        }

        public String getPaymentMethod() {
            return paymentMethod;
        }

        public void setPaymentMethod(String paymentMethod) {
            this.paymentMethod = paymentMethod;
        }

        public Project getProject(){
            return getPaymentId().getProject();
        }

        public Action getAction(){
            return getPaymentId().getAction();
        }

        public void setAction(Action action){
            getPaymentId().setAction(action);
        }

        public void setProject(Project project){
            getPaymentId().setProject(project);
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 89 * hash + this.amount;
            hash = 89 * hash + Objects.hashCode(this.paymentMethod);
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Payment other = (Payment) obj;
            if (this.amount != other.amount) {
                return false;
            }
            if (!Objects.equals(this.paymentMethod, other.paymentMethod)) {
                return false;
            }
            return true;
        }




        @Override
        public String toString() {
            return "Payment{" + "amount=" + amount + ", paymentMethod=" + paymentMethod + '}';
        }




    }

PaymentId:

/*
         * To change this template, choose Tools | Templates
         * and open the template in the editor.
         */
        package com.nisid.entities;

        import java.util.Objects;

        /**
         *
         * @author lurtzaki
         */
        public class PaymentID {

            private Project myproject;
            private Action myaction ;

            public PaymentID(){
            super();}


            public Project getProject() {
                return myproject;
            }

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






    public Action getAction() {
                    return myaction;
                }
            public void setAction(Action action) {
                this.myaction = action;
            }

            @Override
            public int hashCode() {
                int hash = 3;
                hash = 17 * hash + Objects.hashCode(this.myproject);
                hash = 17 * hash + Objects.hashCode(this.myaction);
                return hash;
            }

            @Override
            public boolean equals(Object obj) {
                if (obj == null) {
                    return false;
                }
                if (getClass() != obj.getClass()) {
                    return false;
                }
                final PaymentID other = (PaymentID) obj;
                if (!Objects.equals(this.myproject, other.myproject)) {
                    return false;
                }
                if (!Objects.equals(this.myaction, other.myaction)) {
                    return false;
                }
                return true;
            }



        }

New XML:

<composite-id name="paymentId"         class="com.nisid.entities.PaymentID">
        <key-many-to-one name="myproject" class="com.nisid.entities.Project">
            <column name="projectId"/>
         </key-many-to-one>
         <key-many-to-one name="myaction" class="com.nisid.entities.Action">
            <column name="actionId" />
         </key-many-to-one>
    </composite-id>
    <property name="amount" column="amount" type="int"/> 
    <property name="paymentDate" column="paymentDate" type="date"/> 
    <property name="paymentExpire" column="paymentExpire" type="date"/> 
    <property name="paymentMethod" column="paymentMethod" type="string"/>
1

There are 1 best solutions below

19
On

if you need paymentMethod, price, startDate, endDate in your payment table then you need 3 entities mapping. you can map action and project many to many to each other using payment table as its join table. or if you have trouble searching for example of many to many with join table, you can also use many to one for each table action and project, to tabe payment.

edit:

try to test project and payment first, delete other potential error relation, if you success with it, you can implement it to other table. I thing the xml relation will be like this:

in the project.hbm.xml change the one-to-many became like this:

<list name="payments"
        inverse="true"
        cascade="save-update">
    <key column="projectId"/>
    <index column="actionId"/>
    <one-to-many class="Payment"/>
</list>

in the action.hbm.xml change the one-to-many became like this:

<list name="payments"
        inverse="true"
        cascade="save-update">
    <key column="actionId"/>
    <index column="projectId"/>
    <one-to-many class="Payment"/>
</list>

and in the payments.hbm.xml like this(i thing you dont need <component> tag there):

<hibernate-mapping>
    <class name="com.nisid.entities.Payment" table="payments">


        <composite-id name="paymentId" class="com.nisid.entities.PaymentID" >

            <key-property name="myproject" column="projectId" />
            <key-property name="myaction" column="actionId" />

        </composite-id>

        <many-to-one name="project" column="projectId" insert="false" update="false" not-null="true"/>
        <many-to-one name="action" column="actionId" insert="false" update="false" not-null="true"/>

        <property name="amount" column="amount" type="int"/> 
        <property name="paymentDate" column="paymentDate" type="date"/> 
        <property name="paymentExpire" column="paymentExpire" type="date"/> 
        <property name="paymentMethod" column="paymentMethod" type="string"/>

    </class>