父表的主键是子表的主键,如何使用jpa进行映射?
Posted
技术标签:
【中文标题】父表的主键是子表的主键,如何使用jpa进行映射?【英文标题】:The primary key of the parent table is the primary key of the child table, How can I map it using jpa? 【发布时间】:2021-12-10 00:19:52 【问题描述】:这是图表:
参考:https://docs.spring.io/spring-batch/docs/current/reference/html/index-single.html
我从 batch_job_execution_params 表中获取列表,但数据与第一行中的信息重复,计数正确。
我的实体类如下:
BATCH_JOB_EXECUTION 表
package com.maxcom.interfact_services.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
@Entity
@Table(name = "BATCH_JOB_EXECUTION")
public class BatchJobExecutionEntity implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JOB_EXECUTION_ID", nullable = false)
private Long jobExecutionId;
@Column(name = "VERSION")
private Long version;
@ManyToOne
@JoinColumn(name = "JOB_INSTANCE_ID", nullable = false, updatable = false)
private BatchJobInstanceEntity jobInstanceId;
@Column(name = "CREATE_TIME")
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
@Column(name = "START_TIME")
@Temporal(TemporalType.TIMESTAMP)
private Date startTime;
@Column(name = "END_TIME")
@Temporal(TemporalType.TIMESTAMP)
private Date endTime;
@Column(name = "STATUS")
private String status;
@Column(name = "EXIT_CODE")
private String exitCode;
@Column(name = "EXIT_MESSAGE")
private String exitMessage;
@Column(name = "LAST_UPDATED")
@Temporal(TemporalType.TIMESTAMP)
private Date lastUpdated;
@Column(name = "JOB_CONFIGURATION_LOCATION")
private String jobConfigurationLocation;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "batchJobExecutionEntity", orphanRemoval = true)
private Set<BatchStepExecutionEntity> batchSteps;
@JsonManagedReference
@MapsId("jobExecutionId")
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "jobExecutionId", orphanRemoval = true)
// @JsonIgnoreProperties("batchJobExecutionEntity")
private List<BatchJobExecutionParamsEntity> batchJobParams = new ArrayList<>();
public BatchJobExecutionEntity()
public Long getJobExecutionId()
return jobExecutionId;
public void setJobExecutionId(Long jobExecutionId)
this.jobExecutionId = jobExecutionId;
public Long getVersion()
return version;
public void setVersion(Long version)
this.version = version;
@JsonBackReference
public BatchJobInstanceEntity getJobInstanceId()
return jobInstanceId;
public void setJobInstanceId(BatchJobInstanceEntity jobInstanceId)
this.jobInstanceId = jobInstanceId;
public Date getCreateTime()
return createTime;
public void setCreateTime(Date createTime)
this.createTime = createTime;
public Date getStartTime()
return startTime;
public void setStartTime(Date startTime)
this.startTime = startTime;
public Date getEndTime()
return endTime;
public void setEndTime(Date endTime)
this.endTime = endTime;
public String getStatus()
return status;
public void setStatus(String status)
this.status = status;
public String getExitCode()
return exitCode;
public void setExitCode(String exitCode)
this.exitCode = exitCode;
public String getExitMessage()
return exitMessage;
public void setExitMessage(String exitMessage)
this.exitMessage = exitMessage;
public Date getLastUpdated()
return lastUpdated;
public void setLastUpdated(Date lastUpdated)
this.lastUpdated = lastUpdated;
public String getJobConfigurationLocation()
return jobConfigurationLocation;
public void setJobConfigurationLocation(String jobConfigurationLocation)
this.jobConfigurationLocation = jobConfigurationLocation;
@JsonManagedReference
public Set<BatchStepExecutionEntity> getBatchSteps()
return batchSteps;
public void setBatchSteps(Set<BatchStepExecutionEntity> batchSteps)
this.batchSteps = batchSteps;
public List<BatchJobExecutionParamsEntity> getBatchJobParams()
return batchJobParams;
public void setBatchJobParams(List<BatchJobExecutionParamsEntity> batchJobParams)
this.batchJobParams = batchJobParams;
BATCH_JOB_EXECUTION_PARAMS 表
package com.maxcom.interfact_services.entity;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table(name = "BATCH_JOB_EXECUTION_PARAMS")
public class BatchJobExecutionParamsEntity implements Serializable
@Id
// @GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "JOB_EXECUTION_ID", length = 20)
private Long jobExecutionId;
// @JsonBackReference
// @ManyToOne(fetch = FetchType.LAZY)
// @JoinColumn(name= "JOB_EXECUTION_ID", insertable = false, updatable = false)
// @JsonIgnoreProperties("batchJobParams")
// private BatchJobExecutionEntity batchJobExecutionEntity;
@Column(name = "TYPE_CD", length = 6)
private String typeCd;
@Column(name = "KEY_NAME", length = 100)
private String keyName;
@Column(name = "STRING_VAL", length = 250)
private String stringVal;
@Column(name = "DATE_VAL")
@Temporal(TemporalType.TIMESTAMP)
private Date dateVal;
@Column(name = "LONG_VAL")
private Long longVal;
@Column(name = "DOUBLE_VAL")
private Double doubleVal;
@Column(name = "IDENTIFYING", columnDefinition = "char(1)")
private String identifying;
public BatchJobExecutionParamsEntity()
public Long getJobExecutionId()
return jobExecutionId;
public void setJobExecutionId(Long jobExecutionId)
this.jobExecutionId = jobExecutionId;
public String getTypeCd()
return typeCd;
public void setTypeCd(String typeCd)
this.typeCd = typeCd;
public String getKeyName()
return keyName;
public void setKeyName(String keyName)
this.keyName = keyName;
public String getStringVal()
return stringVal;
public void setStringVal(String stringVal)
this.stringVal = stringVal;
public Date getDateVal()
return dateVal;
public void setDateVal(Date dateVal)
this.dateVal = dateVal;
public Long getLongVal()
return longVal;
public void setLongVal(Long longVal)
this.longVal = longVal;
public Double getDoubleVal()
return doubleVal;
public void setDoubleVal(Double doubleVal)
this.doubleVal = doubleVal;
public String getIdentifying()
return identifying;
public void setIdentifying(String identifying)
this.identifying = identifying;
/*
public BatchJobExecutionEntity getBatchJobExecutionEntity()
return batchJobExecutionEntity;
public void setBatchJobExecutionEntity(BatchJobExecutionEntity batchJobExecutionEntity)
this.batchJobExecutionEntity = batchJobExecutionEntity;
*/
如何映射此场景的1:N?
【问题讨论】:
对于 1:N,BatchJobExecutionParamsEntity
需要的不仅仅是 jobExecutionId
作为@Id
。唯一标识它的其他字段是什么?
感谢@BrianVosburgh,解决方案是 EmbeddedId。下面我添加我的解决方案,再次感谢您的回复。
【参考方案1】:
拥有非唯一主键是灾难的根源 (/duplicates)。 你错过了Appendix B.3:
请注意,此表没有主键。这是因为框架对一个没有用处,因此不需要它。如果需要,您可以添加一个主键,该主键可以与数据库生成的键一起添加,而不会对框架本身造成任何问题。
因此,您可以将生成的主键添加到表中并将其用作 Id,或者在 BatchJobExecutionParamsEntity 上创建一个 EmbeddedId / IdClass 以及所有字段。
【讨论】:
【参考方案2】:我的解决方案基于@Lookslikeitsnot 的回答以及以下文章:https://fullstackdeveloper.guru/2021/08/25/what-is-mapsid-used-for-in-jpa-hibernate-part-ii/
这个场景中的关键字是:
@Embeddable @EmbeddedId @MapsId我分享我的最终代码:
- BatchJobExecutionParamsEntity:(子表)
package com.maxcom.interfact_services.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "BATCH_JOB_EXECUTION_PARAMS")
public class BatchJobExecutionParamsEntity implements Serializable
@EmbeddedId
private BatchJobParamIdEmbedded id;
@JsonBackReference
@ManyToOne
@MapsId("jobExecutionId")
@JoinColumn(name= "JOB_EXECUTION_ID", insertable = false, updatable = false)
private BatchJobExecutionEntity batchJobExecutionEntity;
public BatchJobExecutionParamsEntity()
public BatchJobParamIdEmbedded getId()
return id;
public void setId(BatchJobParamIdEmbedded id)
this.id = id;
public BatchJobExecutionEntity getBatchJobExecutionEntity()
return batchJobExecutionEntity;
public void setBatchJobExecutionEntity(BatchJobExecutionEntity batchJobExecutionEntity)
this.batchJobExecutionEntity = batchJobExecutionEntity;
- BatchJobParamIdEmbedded:(嵌入式实体)
package com.maxcom.interfact_services.entity;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.io.Serializable;
import java.util.Date;
@Embeddable
public class BatchJobParamIdEmbedded implements Serializable
private Long jobExecutionId; // composite key class
@Column(name = "TYPE_CD", length = 6)
private String typeCd;
@Column(name = "KEY_NAME", length = 100)
private String keyName;
@Column(name = "STRING_VAL", length = 250)
private String stringVal;
@Column(name = "DATE_VAL")
@Temporal(TemporalType.TIMESTAMP)
private Date dateVal;
@Column(name = "LONG_VAL")
private Long longVal;
@Column(name = "DOUBLE_VAL")
private Double doubleVal;
@Column(name = "IDENTIFYING", columnDefinition = "char(1)")
private String identifying;
public Long getJobExecutionId()
return jobExecutionId;
public void setJobExecutionId(Long jobExecutionId)
this.jobExecutionId = jobExecutionId;
public String getTypeCd()
return typeCd;
public void setTypeCd(String typeCd)
this.typeCd = typeCd;
public String getKeyName()
return keyName;
public void setKeyName(String keyName)
this.keyName = keyName;
public String getStringVal()
return stringVal;
public void setStringVal(String stringVal)
this.stringVal = stringVal;
public Date getDateVal()
return dateVal;
public void setDateVal(Date dateVal)
this.dateVal = dateVal;
public Long getLongVal()
return longVal;
public void setLongVal(Long longVal)
this.longVal = longVal;
public Double getDoubleVal()
return doubleVal;
public void setDoubleVal(Double doubleVal)
this.doubleVal = doubleVal;
public String getIdentifying()
return identifying;
public void setIdentifying(String identifying)
this.identifying = identifying;
- BatchJobExecutionEntity:(父表)
package com.maxcom.interfact_services.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "BATCH_JOB_EXECUTION")
public class BatchJobExecutionEntity implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JOB_EXECUTION_ID", nullable = false)
private Long jobExecutionId;
@Column(name = "VERSION")
private Long version;
@ManyToOne
@JoinColumn(name = "JOB_INSTANCE_ID", nullable = false, updatable = false)
private BatchJobInstanceEntity jobInstanceId;
@Column(name = "CREATE_TIME")
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
@Column(name = "START_TIME")
@Temporal(TemporalType.TIMESTAMP)
private Date startTime;
@Column(name = "END_TIME")
@Temporal(TemporalType.TIMESTAMP)
private Date endTime;
@Column(name = "STATUS")
private String status;
@Column(name = "EXIT_CODE")
private String exitCode;
@Column(name = "EXIT_MESSAGE")
private String exitMessage;
@Column(name = "LAST_UPDATED")
@Temporal(TemporalType.TIMESTAMP)
private Date lastUpdated;
@Column(name = "JOB_CONFIGURATION_LOCATION")
private String jobConfigurationLocation;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "batchJobExecutionEntity", orphanRemoval = true)
private List<BatchStepExecutionEntity> batchSteps;
@JsonManagedReference
@OneToMany(mappedBy = "batchJobExecutionEntity", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<BatchJobExecutionParamsEntity> batchJobParams = new ArrayList<>();
public BatchJobExecutionEntity()
public Long getJobExecutionId()
return jobExecutionId;
public void setJobExecutionId(Long jobExecutionId)
this.jobExecutionId = jobExecutionId;
public Long getVersion()
return version;
public void setVersion(Long version)
this.version = version;
@JsonBackReference
public BatchJobInstanceEntity getJobInstanceId()
return jobInstanceId;
public void setJobInstanceId(BatchJobInstanceEntity jobInstanceId)
this.jobInstanceId = jobInstanceId;
public Date getCreateTime()
return createTime;
public void setCreateTime(Date createTime)
this.createTime = createTime;
public Date getStartTime()
return startTime;
public void setStartTime(Date startTime)
this.startTime = startTime;
public Date getEndTime()
return endTime;
public void setEndTime(Date endTime)
this.endTime = endTime;
public String getStatus()
return status;
public void setStatus(String status)
this.status = status;
public String getExitCode()
return exitCode;
public void setExitCode(String exitCode)
this.exitCode = exitCode;
public String getExitMessage()
return exitMessage;
public void setExitMessage(String exitMessage)
this.exitMessage = exitMessage;
public Date getLastUpdated()
return lastUpdated;
public void setLastUpdated(Date lastUpdated)
this.lastUpdated = lastUpdated;
public String getJobConfigurationLocation()
return jobConfigurationLocation;
public void setJobConfigurationLocation(String jobConfigurationLocation)
this.jobConfigurationLocation = jobConfigurationLocation;
@JsonManagedReference
public List<BatchStepExecutionEntity> getBatchSteps()
return batchSteps;
public void setBatchSteps(List<BatchStepExecutionEntity> batchSteps)
this.batchSteps = batchSteps;
public List<BatchJobExecutionParamsEntity> getBatchJobParams()
return batchJobParams;
public void setBatchJobParams(List<BatchJobExecutionParamsEntity> batchJobParams)
this.batchJobParams = batchJobParams;
/* Add an batchJobParam to jobExecution Entity to maintain the bi-directional OneToMapping */
public void addBatchJobExecutionParam(BatchJobExecutionParamsEntity batchJobParam)
this.batchJobParams.add(batchJobParam);
batchJobParam.setBatchJobExecutionEntity(this);
如下图所示,我现在得到不同的对象,当然是封装在id(BatchJobParamIdEmbedded)中:
第二张图片显示更多细节:
感谢大家的支持。
最好的问候
【讨论】:
以上是关于父表的主键是子表的主键,如何使用jpa进行映射?的主要内容,如果未能解决你的问题,请参考以下文章