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;
}