JPA 在具有不同列名的复合键之间映射一对多



我试图从 LEGACY 数据库模式制作 jpa 模型。

我在mysql中创建了一个简单的数据库,并使用eclipse(反向)中的jpa工具生成了模型。

jpa 工具生成的代码在我的 springboot 项目中给出了一个错误:

org.springframework.beans.factory.BeanCreationException:创建名为"entityManagerFactory"的 bean 时出错 在类路径资源 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class] 中定义:

初始化方法的调用失败;嵌套异常是 org.hibernate.AnnotationException: referencedColumnNames(id) of stackoverflow.entity.SecondTable.mainTable 引用 stackoverflow.entity.MainTable 未映射到单个属性

我认为这是有道理的,因为在SecondTable中我的PK是(id,day),而在MainTable中是(id,年,月,代码)。 现在的想法是让id相关。

几个链接: https://gigsterous.github.io/engineering/2016/09/25/spring-boot-2.html

对于属性覆盖(可以指定不相关的列) http://techqa.info/programming/question/33620473/hibernate-bidirectional-one-to-many-with-composite-key

JPA:具有复合主键和单键的实体映射

这些是 jpa 工具创建的 4 个实体:

@Entity
@Table(name="main_table")
public class MainTable implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private MainTablePK id;
private String comment;
//bi-directional many-to-one association to SecondTable
@OneToMany(mappedBy="mainTable")
private List<SecondTable> secondTables;
public MainTable() {
}
}
@Embeddable
public class MainTablePK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
private int id;
private String year;
private String month;
private String code;
public MainTablePK() {
}
}
@Entity
@Table(name="second_table")
public class SecondTable implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private SecondTablePK id;

//bi-directional many-to-one association to MainTable
//I think I don’t need a bi-directional relationship, just from MainTable to SecondTable
//ERROR: NOT MAPPED TO A SINGLE PROPERTY
//I understand id in MainTable is a composite Key
@ManyToOne
@JoinColumn(name="id", referencedColumnName="id")
private MainTable mainTable;

public SecondTable() {
}
}

@Embeddable
public class SecondTablePK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
private int id;
private int day;
private int value1;
private int value2;
private int value3;
public SecondTablePK() {
}
}

脚本 SQL 和数据示例

DROP TABLE IF EXISTS `main_table`;
CREATE TABLE `main_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`year` char(4) NOT NULL,
`month` char(2) NOT NULL,
`code` char(6) NOT NULL,
`comment` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`,`year`,`month`,`code`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
INSERT INTO `main_table` VALUES (1,'2017','01','333090','coment one');
This has a composite key
DROP TABLE IF EXISTS `second_table`;
CREATE TABLE `second_table` (
`id` int(11) NOT NULL,
`day` int(11) NOT NULL,
`value1` int(11) DEFAULT NULL,
`value2` int(11) DEFAULT NULL,
`value3` int(11) DEFAULT NULL,
PRIMARY KEY (`id`,`day`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `second_table` VALUES (1,0,1,NULL,NULL),(1,1,2,NULL,NULL),(1,2,NULL,NULL,NULL),(1,3,NULL,NULL,NULL),(1,4,NULL,NULL,NULL),(1,32,NULL,NULL,NULL);

是否可以使用 JPA 实现? 有什么建议吗?

谢谢

更新

删除了非 PK 字段值 1、值 2 和值 3 是拼写错误。

遵循 JPA 2.1 规范,第2.4.1 节,示例 2,第 34,35 页与我的非常相似。

所以申请:

@MapsId("empPK")
@JoinColumns({
@JoinColumn(name="FK1", referencedColumnName="firstName"),
@JoinColumn(name="FK2", referencedColumnName="lastName") })

我们有:

@ManyToOne
@MapsId("id") // maps the 'id' attribute of the embedded ID
@JoinColumn(name="id", referencedColumnName="id")
private MainTable mainTable;

无需再进行任何更改。

我收到下一个错误: org.springframework.beans.factory.BeanCreationException:创建在类路径资源 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class] 中定义名称为"entityManagerFactory"的 Bean 时出错:调用 init 方法失败;嵌套异常是 org.hibernate.AnnotationException:无法在@MapsId中找到列引用 映射:代码

如果我删除代码,同样的错误,但有月份,如果我删除月份,同样的错误与年份

谢谢

首先,您的SecondTablePK似乎不正确,因为它包括非PK字段value1value2value3。它可能应该是这样的:

@Embeddable
public class SecondTablePK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
private int id;
private int day;
public SecondTablePK() {
}
}

至于共享id:通常,依赖实体将引用父实体的整个主键,但您可能能够像这样映射关系:

@Entity
@Table(name="second_table")
public class SecondTable implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private SecondTablePK id;
private int value1;
private int value2;
private int value3;
@ManyToOne
@MapsId("id") // maps the 'id' attribute of the embedded ID
@JoinColumn(name="id", referencedColumnName="id")
private MainTable mainTable;

public SecondTable() {
}
}

这很像 JPA 2.1 规范第 2.4.1 节中讨论的"派生身份"。