我有一个现有的 JPA 实体(“引用”),其 ID 列作为其从基类“BaseEntity”继承的主键(使用超类上的 @MappedSuperclass 注释)。
我在引用和另一个名为 Violation 的实体之间也有 1-M 关系。违规以前是使用外键“REFERENCE_ID”定义的,指向参考实体的“ID”列。
最近,我尝试在 Reference 实体中添加一个不相关的复合键。这不应该影响参考和违规之间的 1-M 关系。但是,当我在我的 tomcat 服务器中运行代码时,我会看到以下堆栈跟踪:
引起:org.hibernate.AnnotationException:org.qcri.copydetection.sdk.metastore.entity.Violation.reference 的 referencedColumnNames(ID) 引用 org.qcri.copydetection.sdk.metastore.entity.Reference 未映射到单个属性org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:205) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final] at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java :110) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final] at org.hibernate.cfg.AnnotationConfiguration.processEndOfQueue(AnnotationConfiguration.java:541) ~[hibernate-annotations-3.5.6- Final.jar:3.5.6-Final] 在 org.hibernate.cfg.AnnotationConfiguration.processFkSecondPassInOrder(AnnotationConfiguration.java:523) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final] 在 org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:380) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final] 在 org.hibernate.cfg.Configuration。 buildMappings(Configuration.java:1206) ~[hibernate-core-3.5.6-Final.jar:3.5.6-Final] at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1459) ~[hibernate-entitymanager -3.5.6-Final.jar:3.5.6-Final] 在 org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:193) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6- Final] at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1086) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final] at org.hibernate.ejb.Ejb3Configuration.configure( Ejb3Configuration.java:685) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final] 在 org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:73) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final] 在 org.springframework。 orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:268) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java :310)~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)~[spring-beans- 3.1.2.RELEASE.jar:3.1.2.RELEASE] 在 org.springframework.beans.factory.support。AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] ...省略了39个常用框架
以下是所涉及的 3 个类的代码:
@Entity
@Table(name = "REFERENCE")
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@IdClass(Reference.ContextualName.class)
public class Reference extends BaseEntity {
@Column(name= "LOCATION", unique=true)
@XmlElement
private String location;
@Id
@AttributeOverrides({
@AttributeOverride(name = "name", column = @Column(name = "NAME")),
@AttributeOverride(name = "account", column = @Column(name = "ACCOUNT_ID"))
})
@Column(name = "NAME")
@XmlElement
private String name;
@ManyToOne(optional=false)
@XmlTransient
@JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")
private Account account;
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Reference() {}
public Reference(String name) {
setName(name);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public Account getAccount() {
return this.account;
}
public void setAccount(Account account) {
this.account = account;
}
@Embeddable
private class ContextualName implements Serializable {
private static final long serialVersionUID = -3687389984589209378L;
@Basic(optional = false)
@Column(name = "NAME")
@XmlElement
private String name;
@ManyToOne(optional=false)
@XmlTransient
@JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")
private Account account;
ContextualName() {}
}
}
@MappedSuperclass
@XmlAccessorType(XmlAccessType.FIELD)
public abstract class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
@XmlElement
private Long id;
@Basic(optional = true)
@Column(name = "CREATED", insertable = false, updatable = false, columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
@Temporal(TemporalType.TIMESTAMP)
@XmlElement
private Date creationDate;
protected BaseEntity() {}
public Long getId() {
return id;
}
public void setId(Long id) {
if(this.id==null) {
this.id = id;
} else if (this.id!=id) {
throw new IllegalArgumentException("Cannot change the id after it has been set, as it is a generated field.");
}
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
if(this.creationDate==null) {
this.creationDate = creationDate;
} else if (this.creationDate!=creationDate) {
throw new IllegalArgumentException("Cannot change the creation-date after it has been set, as it is a generated field.");
}
}
}
@Entity
@Table(name = "VIOLATION")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Violation extends BaseEntity {
@ManyToOne (optional=false, fetch= FetchType.EAGER)
@JoinColumn(name = "REFERENCE_ID", referencedColumnName = "ID")
private Reference reference;
@ManyToOne (optional=false, fetch= FetchType.EAGER)
@JoinColumn(name = "SUSPECT_ID", referencedColumnName = "ID")
private Suspect suspect;
@ManyToOne (optional=false, fetch= FetchType.EAGER)
@XmlTransient
@JoinColumn(name = "SEARCH_ID", referencedColumnName = "ID")
private Search search;
@Basic(optional = false)
@Column(name = "SCORE")
@XmlElement
private double score;
public Violation() {}
public Violation(Search search, Reference ref, Suspect sus, double score) {
this.search = search;
this.reference = ref;
this.suspect = sus;
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public Reference getReference() {
return reference;
}
public void setReference(Reference reference) {
this.reference = reference;
}
public Suspect getSuspect() {
return suspect;
}
public void setSuspect(Suspect suspect) {
this.suspect = suspect;
}
public Search getSearch() {
return search;
}
public void setSearch(Search search) {
if(this.search!=null && this.search!=search) {
this.search.removeViolation(this);
}
this.search = search;
if(search!=null) {
if(!search.getViolations().contains(this)) {
search.addViolation(this);
}
}
}
}
长话短说,我完全不知道如何将复合键添加到已经具有 ID 列的现有(旧)实体。我无法删除 ID 列,也无法更改 Reference 和 Violation 之间的 1-M 关系。我一生都无法理解错误消息,因为 Violation 实体的“REFERENCE_ID”外键列被映射到引用实体的单个“ID”列。
提前谢谢了!