Given the following tables:
Car
int id PK
int modelId FK
CarDetails
int carId PK, FK to Car.id
varchar(50) description
How would I indicate that the @Id
of CarDetails
is also a foreign key to Car
?
I've tried:
@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
}
However, I get the error
org.hibernate.MappingException: Composite-id class must implement Serializable: com.example.CarDetails
After implementing Serializable
I get This class [class com.example.CarDetails] does not define an IdClass
. But I still get the error after adding @IdClass(Car.class)
to the CarDetails
class.
UPDATE
The IdClass
error originates from 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
Here's the CarDetailsRepository:
public interface CarDetailsRepository extends JpaRepository<CarDetails, Car> {
}
Here are the relevant parts of my gradle build file:
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') }
}
Implementing With a Foreign Key in JPA. Note that we place the @OneToOne annotation on the related entity field, Address. Also, we need to place the @JoinColumn annotation to configure the name of the column in the users table that maps to the primary key in the address table.
You can use JPA's @MapsId annotation to tell Hibernate that it shall use the foreign key of an associated entity as the primary key. Let's take a look at a simple example. Each Book has a Manuscript, and each Manuscript belongs to 1 Book. The foreign key of the Book is also the primary key of the Manuscript.
So yes, you can have more than one @Id. Or is it @EmbeddedId? I can't remember if @EmbeddedId is currently there, or if it is still in discussion by the JSR group for the next version of JPA. JPA 1.0 currently supports two different approaches for compound PKs.
Introduction to Composite Primary Keys and Primary Key Classes. The EJB 3.0 specification allows you to define a primary key class as a @Embeddable and use it as the primary key of your Entity bean. One or more properties can be used as members of the primary key for that particular table.
Probably the best way is to reference carId
twice in your CarDetails
entity--once for the @Id and once for the foreign key reference. You must declare one of these references with insertable=false
and updatable=false
so that JPA doesn't get confused trying to manage the same column in two spots:
@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
}
It looks odd, but it'll work and it's actually the (most) preferred method.
You might try mapping CarDetails
like this:
@Entity
public class CarDetails {
@Id
private int id;
@MapsId
@OneToOne
@JoinColumn(name = "carId", nullable = false)
private Car car;
private String description;
//setters & getters
}
Note the @MapsId
annotation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With