JPA 2 - 如何使用 Spring Data JPA 构建具有主键同时也是外键的实体?
JPA 2 - How to build entity that has Primary key that is also a foreign key using Spring Data JPA?
给定下表:
Car
int id PK
int modelId FK
CarDetails
int carId PK, FK to Car.id
varchar(50) description
如何表示 CarDetails
的 @Id
也是 Car
的外键?
我试过:
@Entity
public class Car {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne
@JoinColumn(name = "modelId", nullable = false)
private Model model;
//setters & getters
}
@Entity
public class CarDetails {
@Id
@OneToOne
@JoinColumn(name = "carId", nullable = false)
private Car car;
private String description;
//setters & getters
}
但是,我得到了错误
org.hibernate.MappingException: Composite-id class must implement Serializable: com.example.CarDetails
实施 Serializable
后,我得到 This class [class com.example.CarDetails] does not define an IdClass
。但是在将 @IdClass(Car.class)
添加到 CarDetails
class 后我仍然得到错误。
更新
IdClass
错误源自 Spring:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'carDetailsRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: This class [class com.example.CarDetails] does not define an IdClass
这是 CarDetailsRepository:
public interface CarDetailsRepository extends JpaRepository<CarDetails, Car> {
}
以下是我的 gradle 构建文件的相关部分:
plugins {
id 'java'
id 'eclipse'
id 'maven-publish'
id 'io.spring.dependency-management' version '1.0.3.RELEASE'
}
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
pmd group: 'org.hibernate', name: 'hibernate-tools', version: '5.2.3.Final'
pmd group: 'org.hibernate', name: 'hibernate-core', version: '5.2.10.Final'
pmd group: 'org.hibernate.common', name: 'hibernate-commons-annotations', version: '5.0.1.Final'
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.hibernate:hibernate-validator:5.2.4.Final')
compile('org.hibernate:hibernate-envers:5.2.10.Final')
compile('org.hibernate:hibernate-core:5.2.10.Final')
compile('org.hibernate.common:hibernate-commons-annotations:5.0.1.Final')
runtime('net.sourceforge.jtds:jtds:1.3.1')
runtime('com.microsoft.sqlserver:sqljdbc:4.2')
runtime('javax.el:javax.el-api:2.2.4')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports { mavenBom('org.springframework.boot:spring-boot-dependencies:1.5.4.RELEASE') }
}
可能最好的方法是在您的 CarDetails
实体中引用 carId
两次——一次用于 @Id,一次用于外键引用。您必须使用 insertable=false
和 updatable=false
声明这些引用之一,这样 JPA 就不会在尝试在两个位置管理同一列时感到困惑:
@Entity
public class CarDetails {
@Id
@Column(name = "carId", insertable = false, updatable = false)
private int carId; // don't bother with getter/setter since the `car` reference handles everything
@OneToOne
@JoinColumn(name = "carId", nullable = false)
private Car car;
private String description;
//setters & getters
}
它看起来很奇怪,但它会起作用,而且它实际上是(最)首选的方法。
您可以尝试这样映射 CarDetails
:
@Entity
public class CarDetails {
@Id
private int id;
@MapsId
@OneToOne
@JoinColumn(name = "carId", nullable = false)
private Car car;
private String description;
//setters & getters
}
注意 @MapsId
注释。
给定下表:
Car
int id PK
int modelId FK
CarDetails
int carId PK, FK to Car.id
varchar(50) description
如何表示 CarDetails
的 @Id
也是 Car
的外键?
我试过:
@Entity
public class Car {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne
@JoinColumn(name = "modelId", nullable = false)
private Model model;
//setters & getters
}
@Entity
public class CarDetails {
@Id
@OneToOne
@JoinColumn(name = "carId", nullable = false)
private Car car;
private String description;
//setters & getters
}
但是,我得到了错误
org.hibernate.MappingException: Composite-id class must implement Serializable: com.example.CarDetails
实施 Serializable
后,我得到 This class [class com.example.CarDetails] does not define an IdClass
。但是在将 @IdClass(Car.class)
添加到 CarDetails
class 后我仍然得到错误。
更新
IdClass
错误源自 Spring:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'carDetailsRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: This class [class com.example.CarDetails] does not define an IdClass
这是 CarDetailsRepository:
public interface CarDetailsRepository extends JpaRepository<CarDetails, Car> {
}
以下是我的 gradle 构建文件的相关部分:
plugins {
id 'java'
id 'eclipse'
id 'maven-publish'
id 'io.spring.dependency-management' version '1.0.3.RELEASE'
}
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
pmd group: 'org.hibernate', name: 'hibernate-tools', version: '5.2.3.Final'
pmd group: 'org.hibernate', name: 'hibernate-core', version: '5.2.10.Final'
pmd group: 'org.hibernate.common', name: 'hibernate-commons-annotations', version: '5.0.1.Final'
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.hibernate:hibernate-validator:5.2.4.Final')
compile('org.hibernate:hibernate-envers:5.2.10.Final')
compile('org.hibernate:hibernate-core:5.2.10.Final')
compile('org.hibernate.common:hibernate-commons-annotations:5.0.1.Final')
runtime('net.sourceforge.jtds:jtds:1.3.1')
runtime('com.microsoft.sqlserver:sqljdbc:4.2')
runtime('javax.el:javax.el-api:2.2.4')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports { mavenBom('org.springframework.boot:spring-boot-dependencies:1.5.4.RELEASE') }
}
可能最好的方法是在您的 CarDetails
实体中引用 carId
两次——一次用于 @Id,一次用于外键引用。您必须使用 insertable=false
和 updatable=false
声明这些引用之一,这样 JPA 就不会在尝试在两个位置管理同一列时感到困惑:
@Entity
public class CarDetails {
@Id
@Column(name = "carId", insertable = false, updatable = false)
private int carId; // don't bother with getter/setter since the `car` reference handles everything
@OneToOne
@JoinColumn(name = "carId", nullable = false)
private Car car;
private String description;
//setters & getters
}
它看起来很奇怪,但它会起作用,而且它实际上是(最)首选的方法。
您可以尝试这样映射 CarDetails
:
@Entity
public class CarDetails {
@Id
private int id;
@MapsId
@OneToOne
@JoinColumn(name = "carId", nullable = false)
private Car car;
private String description;
//setters & getters
}
注意 @MapsId
注释。