Applying Many to Many

many-to-many-header-img1
This is based on this section:


In controller method, it creates a relation ship between RTRN_TP and RTRN_RSN
1. RTRN_RSN object set to HashSet that part of fileds of RTRN_TP
2. RTRN_TP object is saved
many-to-many1
RTRN_RSN of “006”, “010”, and “011” have been bound to RTRN_TP of “01”
many-to-many-data2

@RequestMapping(value = "/cUrlValAttrbSubTpRsn01Jsp", params = "toUnBoundRsnList", method = RequestMethod.POST)
public ModelAndView toUnBoundRsnList(@ModelAttribute("RtrnTpModel") RtrnTpModel tp, ModelMap model, HttpServletRequest req) {

	String tpSelected = (String) req.getSession().getAttribute(CONST.TP_SELECTED.getVal());
	if (CommonBL.hasValue(tpSelected)) {
		List<String> selectedCheckBox = tp.getSelectedCheckBox();
		if (!CommonBL.isEmpty(selectedCheckBox)) {
			for (String code : selectedCheckBox) {
				RTRN_TP_RSN_CMBN tpRsnObj = this.tpRsnSvc.getTpRsnCmbnByHql(tpSelected, code);
				if (tpRsnObj != null) {
					this.tpRsnSvc.delete(tpRsnObj);
				}
			}
		}
	}
	return getMVSubTpRsn01(model, req);
}

Unlike adding the relationship, to delete (un-bound) the relationship, it’s directly deleting the Join Table (RTRN_TP_RSN_CMBN)

Many to Many

many-to-many-header-img1
Many-to-Many mapping is usually implemented a Join Table, suppose we have Type and Reason table and Reason table for many-to-many mapping. Every Type can have more than one Reasons and every Reasons is a part of more than one Type.
2015-05-17_10h45_40

CREATE TABLE `rtrn_tp` (
	`rtrn_tp_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`rtrn_tp_nm` VARCHAR(100) NULL DEFAULT NULL,
	`sort_num` INT(11) UNSIGNED NOT NULL DEFAULT '0',
	PRIMARY KEY (`rtrn_tp_cd`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
CREATE TABLE `rtrn_rsn` (
	`rtrn_rsn_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`rtrn_rsn_nm` VARCHAR(100) NULL DEFAULT NULL,
	`sort_num` INT(11) UNSIGNED NOT NULL DEFAULT '0',
	PRIMARY KEY (`rtrn_rsn_cd`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
CREATE TABLE `rtrn_tp_rsn_cmbn` (
	`rtrn_tp_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`rtrn_rsn_cd` VARCHAR(20) NOT NULL DEFAULT '',
	PRIMARY KEY (`rtrn_tp_cd`, `rtrn_rsn_cd`),
	INDEX `fk_rtrn_rsn` (`rtrn_rsn_cd`),
	CONSTRAINT `fk_rtrn_rsn` FOREIGN KEY (`rtrn_rsn_cd`) REFERENCES `rtrn_rsn` (`rtrn_rsn_cd`),
	CONSTRAINT `fk_rtrn_tp` FOREIGN KEY (`rtrn_tp_cd`) REFERENCES `rtrn_tp` (`rtrn_tp_cd`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

There is a Join Table, RTRN_TP_RSN_CMBN, only have the relationship between Type (RTRN_TP) and Reason (RTRN_RSN)

package com.ns.spring.model;

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

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "RTRN_TP")
public class RTRN_TP {

	@Id
	@Column(name = "rtrn_tp_cd")
	private String rtrnTpCd;

	@Column(name = "rtrn_tp_nm")
	private String rtrnTpNm;

	@Column(name = "sort_num")
	private int sortNum;

	@ManyToMany(targetEntity = RTRN_RSN.class, cascade = { CascadeType.ALL })
	@JoinTable(name = "RTRN_TP_RSN_CMBN", 
				joinColumns = { @JoinColumn(name = "rtrn_tp_cd") }, 
				inverseJoinColumns = { @JoinColumn(name = "rtrn_rsn_cd") })
	private Set<RTRN_RSN> rtrnRsns = new HashSet<RTRN_RSN>();

	public String getRtrnTpCd() {
		return rtrnTpCd;
	}

	public void setRtrnTpCd(String rtrnTpCd) {
		this.rtrnTpCd = rtrnTpCd;
	}

	public String getRtrnTpNm() {
		return rtrnTpNm;
	}

	public void setRtrnTpNm(String rtrnTpNm) {
		this.rtrnTpNm = rtrnTpNm;
	}

	public int getSortNum() {
		return sortNum;
	}

	public void setSortNum(int sortNum) {
		this.sortNum = sortNum;
	}

	public Set<RTRN_RSN> getRtrnRsns() {
		return rtrnRsns;
	}

	public void setRtrnRsns(Set<RTRN_RSN> rtrnRsns) {
		this.rtrnRsns = rtrnRsns;
	}

	public String toString() {
		return "Type Code:" + this.rtrnTpCd + ", Name:" + this.rtrnTpNm;
	}
}
package com.ns.spring.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "RTRN_RSN")
public class RTRN_RSN {

	@Id
	@Column(name = "rtrn_rsn_cd")
	private String rtrnRsnCd;
	
	@Column(name = "rtrn_rsn_nm")	
	private String rtrnRsnNm;
	
	@Column(name = "sort_num")	
	private int sortNum;

	public String getRtrnRsnCd() {
		return rtrnRsnCd;
	}

	public void setRtrnRsnCd(String rtrnRsnCd) {
		this.rtrnRsnCd = rtrnRsnCd;
	}

	public String getRtrnRsnNm() {
		return rtrnRsnNm;
	}

	public void setRtrnRsnNm(String rtrnRsnNm) {
		this.rtrnRsnNm = rtrnRsnNm;
	}

	public int getSortNum() {
		return sortNum;
	}

	public void setSortNum(int sortNum) {
		this.sortNum = sortNum;
	}

	public String toString() {
		return "Reason Code:" + this.rtrnRsnCd + ", Name:" + this.rtrnRsnNm;
	}
}
package com.ns.spring.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "RTRN_TP_RSN_CMBN")
public class RTRN_TP_RSN_CMBN implements Serializable {

	private static final long serialVersionUID = 4677612728077605784L;

	@Id
	@Column(name = "rtrn_tp_cd")
	private String rtrnTpCd;
	
	@Id
	@Column(name = "rtrn_rsn_cd")
	private String rtrnRsnCd;
	
	public String getRtrnTpCd() {
		return rtrnTpCd;
	}

	public void setRtrnTpCd(String rtrnTpCd) {
		this.rtrnTpCd = rtrnTpCd;
	}

	public String getRtrnRsnCd() {
		return rtrnRsnCd;
	}

	public void setRtrnRsnCd(String rtrnRsnCd) {
		this.rtrnRsnCd = rtrnRsnCd;
	}
	
	public String toString() {
		return "Type" + this.rtrnTpCd + ", Reason:" + this.rtrnRsnCd;
	}
}
@RequestMapping(value = "/cUrlValAttrbSubTpRsn01Jsp", params = "toBoundRsnList", method = RequestMethod.POST)
public ModelAndView toBoundRsnList(@ModelAttribute("RtrnTpModel") RtrnTpModel tp, ModelMap model, HttpServletRequest req) {

	String tpSelected = (String) req.getSession().getAttribute(CONST.TP_SELECTED.getVal());
	if (CommonBL.hasValue(tpSelected)) {
		RTRN_TP tpObj = this.tpSvc.findById(tpSelected);
		if (tpObj != null) {
			List<String> selectedCheckBox = TpRsnBL.getRsnToBound(tp, req);
			if (!CommonBL.isEmpty(selectedCheckBox)) {
				Set<RTRN_RSN> rtrnRsns = new HashSet<RTRN_RSN>();
				for (String code : selectedCheckBox) {
					RTRN_RSN rsnObj = this.rsnSvc.findById(code);
					if (rsnObj != null) {
						rtrnRsns.add(rsnObj);
						tpObj.setRtrnRsns(rtrnRsns);
						this.tpSvc.saveOrUpdate(tpObj);
					}
				}
			}
		}
	}
	return getMVSubTpRsn01(model, req);
}

This is how to use Many to Many in Spring MVC.

One to Many – Composite Primary Key

one-to-many-header-img1
In Hibernate, you need to have special field in order to accomplish a composite primary key to make it as a single key object:
one-to-many-header-comppk1
To handle composite primary key, you need to user an extra class “RmaLinePk”.
2015-06-01_07h41_10

2015-05-17_10h08_28

CREATE TABLE `rma_hdr` (
	`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
	`rma_num` VARCHAR(20) NOT NULL DEFAULT '',
	`rma_hdr_sts_cd` VARCHAR(20) NULL DEFAULT NULL,
	`rtrn_tp_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`rtrn_rsn_cd` VARCHAR(20) NULL DEFAULT NULL,
	`sell_to_cust_cd` VARCHAR(20) NULL DEFAULT NULL,
	PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=27
;
CREATE TABLE `rma_line` (
	`rma_num` VARCHAR(20) NOT NULL DEFAULT '',
	`rma_line_num` VARCHAR(20) NOT NULL DEFAULT '',
	`rma_line_sts_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`mdse_cd` VARCHAR(20) NOT NULL DEFAULT '',
	`qty` INT(11) UNSIGNED NOT NULL DEFAULT '0',
	`rma_id` INT(11) UNSIGNED NOT NULL,
	PRIMARY KEY (`rma_num`, `rma_line_num`),
	INDEX `rma_id` (`rma_id`),
	CONSTRAINT `rma_line_ibfk_1` FOREIGN KEY (`rma_id`) REFERENCES `rma_hdr` (`id`) ON DELETE CASCADE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
package com.ns.spring.model;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import com.ns.spring.model.ui.RmaHdrModel;

/**
 * Entity bean with JPA annotations Hibernate provides JPA implementation
 */
@Entity
@Table(name = "RMA_HDR")
public class RMA_HDR {

	@Id
	@Column(name = "id")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@Column(name = "rma_num")
	private String rmaNum;
	
	@Column(name = "rma_hdr_sts_cd")
	private String rmaHdrStsCd;

	@Column(name = "rtrn_tp_cd")
	private String rtrnTpCd;

	@Column(name = "rtrn_rsn_cd")
	private String rtrnRsnCd;

	@Column(name = "sell_to_cust_cd")
	private String sellToCustCd;

	@OneToMany(mappedBy = "rmaHdr", targetEntity = RMA_LINE.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
	private List<RMA_LINE> rmaLines;
	
	public RMA_HDR(){}

	public RMA_HDR(RmaHdrModel hdr) {
		this.id = hdr.getId();
		this.rmaNum = hdr.getRmaNum();
		this.rmaHdrStsCd = hdr.getRmaHdrStsCd();
		this.rtrnTpCd = hdr.getRtrnTpCd();
		this.rtrnRsnCd = hdr.getRtrnRsnCd();
		this.sellToCustCd = hdr.getSellToCustCd();
	}

	public int getId() {
		return id;
	}

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

	public String getRmaNum() {
		return rmaNum;
	}

	public void setRmaNum(String rmaNum) {
		this.rmaNum = rmaNum;
	}

	public String getRmaHdrStsCd() {
		return rmaHdrStsCd;
	}

	public void setRmaHdrStsCd(String rmaHdrStsCd) {
		this.rmaHdrStsCd = rmaHdrStsCd;
	}

	public String getRtrnTpCd() {
		return rtrnTpCd;
	}

	public void setRtrnTpCd(String rtrnTpCd) {
		this.rtrnTpCd = rtrnTpCd;
	}

	public String getRtrnRsnCd() {
		return rtrnRsnCd;
	}

	public void setRtrnRsnCd(String rtrnRsnCd) {
		this.rtrnRsnCd = rtrnRsnCd;
	}

	public String getSellToCustCd() {
		return sellToCustCd;
	}

	public void setSellToCustCd(String sellToCustCd) {
		this.sellToCustCd = sellToCustCd;
	}

	public List<RMA_LINE> getRmaLines() {
		return rmaLines;
	}

	public void setRmaLines(List<RMA_LINE> rmaLines) {
		this.rmaLines = rmaLines;
	}
	
	public String toString() {
		return "ID:" + this.id + ", RMA_NUM:" + this.rmaNum + ", Status:" + this.rmaHdrStsCd + ", Type:" + this.rtrnTpCd + ", Reason:" + this.rtrnRsnCd;
	}
}
@Id
private RmaLinePk rmaLinePk;

Above:In “many side”, it uses the primary key field

package com.ns.spring.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * Entity bean with JPA annotations Hibernate provides JPA implementation
 */
@Entity
@Table(name = "RMA_LINE")
public class RMA_LINE {

	@Id
	private RmaLinePk rmaLinePk;

	@Column(name = "rma_line_sts_cd")
	private String rmaLineStsCd;

	@Column(name = "mdse_cd")
	private String mdseCd;

	@Column(name = "qty")
	private int qty;

	@ManyToOne
	@JoinColumn(name = "rma_id")
	private RMA_HDR rmaHdr;
	
	public RMA_LINE(){}

	public RmaLinePk getRmaLinePk() {
		return rmaLinePk;
	}

	public void setRmaLinePk(RmaLinePk rmaLinePk) {
		this.rmaLinePk = rmaLinePk;
	}

	public String getRmaLineStsCd() {
		return rmaLineStsCd;
	}

	public void setRmaLineStsCd(String rmaLineStsCd) {
		this.rmaLineStsCd = rmaLineStsCd;
	}

	public String getMdseCd() {
		return mdseCd;
	}

	public void setMdseCd(String mdseCd) {
		this.mdseCd = mdseCd;
	}

	public RMA_HDR getRmaHdr() {
		return rmaHdr;
	}

	public int getQty() {
		return qty;
	}

	public void setQty(int qty) {
		this.qty = qty;
	}

	public void setRmaHdr(RMA_HDR rmaHdr) {
		this.rmaHdr = rmaHdr;
	}

	public String toString() {
		return "PK:" + this.rmaLinePk.toString() + ", Line Status:" + this.rmaLineStsCd + ", Mdse:" + this.mdseCd + ", Qty:" + this.qty;
	}
}
private String rma_num;
private String rma_line_num;

The real primary keys which are composite defines in the following class: RmaLinePk.java

package com.ns.spring.model;

import java.io.Serializable;

import javax.persistence.Embeddable;

@Embeddable
public class RmaLinePk implements Serializable {

	private static final long serialVersionUID = -403250971215465050L;

	private String rma_num;

	private String rma_line_num;

	public RmaLinePk() {
	}

	public RmaLinePk(String rma_num, String rma_line_num) {
		this.rma_num = rma_num;
		this.rma_line_num = rma_line_num;
	}

	public String getRma_num() {
		return rma_num;
	}

	public void setRma_num(String rma_num) {
		this.rma_num = rma_num;
	}

	public String getRma_line_num() {
		return rma_line_num;
	}

	public void setRma_line_num(String rma_line_num) {
		this.rma_line_num = rma_line_num;
	}

	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		RmaLinePk other = (RmaLinePk) obj;
		if (rma_num == null) {
			if (other.rma_num != null) {
				return false;
			}
		} else if (!rma_num.equals(other.rma_num)) {
			return false;
		}
		if (rma_line_num == null) {
			if (other.rma_line_num != null) {
				return false;
			}
		} else if (!rma_line_num.equals(other.rma_line_num)) {
			return false;
		}
		return true;
	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((rma_num == null) ? 0 : rma_num.hashCode());
		result = prime * result	+ ((rma_line_num == null) ? 0 : rma_line_num.hashCode());
		return result;
	}

	public String toString() {
		return "RmaLinePk:RMA#:" + this.rma_num + ", Line#:" + this.rma_line_num;
	}
}

This is how the data is stored in controller: See also Submitting a collection.

public ModelAndView submitLine(@ModelAttribute("rmaLineListModel") RmaLineListModel rmaLineListModel, Model model, HttpServletRequest req) {

	String rmaNum = rmaLineListModel.getRmaNum();
	List<RmaLineModel> currList = rmaLineListModel.getRmaLineModelList();
	if (!CommonBL.isEmpty(currList)) {
		for (RmaLineModel obj : currList) {
			String rmaLineNum = obj.getRmaLineNum();
			List<RmaLineModel> rmaLinsList = RmaDtlBL.getRmaLineListWithCdTblNm(rmaNum, rmaLineNum);
			if (CommonBL.isEmpty(rmaLinsList)) {
				// New Record
				this.rmaLineSvc.save(RmaDtlBL.getRmaLineObj(obj, rmaNum, rmaLineNum));
			}
		}
	}
	List<RmaLineModel> rmaLineModelList = RmaDtlBL.getRmaLineListWithCdTblNm(rmaNum, null);
	return getMVSubLine01(rmaNum, rmaLineModelList, req);
}

This method passes the object to be inserted/updated

public static RMA_LINE getRmaLineObj(RmaLineModel obj, String rmaNum, String rmaLineNum) {
	RMA_LINE rmaLine = new RMA_LINE();
	rmaLine.setRmaLinePk(new RmaLinePk(rmaNum, rmaLineNum));
	rmaLine.setRmaHdr(RmaBL.getRmaHdrObj(rmaNum));
	rmaLine.setRmaLineStsCd(getStsCd(obj.getRmaLineStsCd()));
	rmaLine.setMdseCd(obj.getMdseCd());
	rmaLine.setQty(obj.getQty());
	return rmaLine;
}