I have two tables, each with a composite key:
CREATE TABLE Software (
id int not null,
version int not null,
PRIMARY KEY (id, version)
);
CREATE TABLE System (
name char(10) not null,
version int not null,
PRIMARY KEY (name, version)
);
Now, I need an association where I can express the concept "a Software has minimum requirements on the version of the System where it can run". The following table does it at the DB level:
CREATE TABLE Requirement (
software_id int not null,
software_version int not null,
system_name char(10) not null,
system_version int not null,
PRIMARY KEY (software_id, software_version, system_name),
FOREIGN KEY (software_id, software_version) REFERENCES Software (id,version),
FOREIGN KEY (system_name, system_version) REFERENCES System (name,version)
)
Note that Requirement has three fields as primary key. If I were to make all four primary, then I could express more than one requirement for a software (ie OpenLib v1.2 depends on Ubuntu 13.04 and on Ubuntu 13.10), whereas a software can only have one requirement for a given OS (in the example, OpenLib v1.2 depends on Ubuntu 13.04).
How can I map this to JPA/Hibernate @Entity objects (using annotations)? (Including the related OneToMany/ManyToOne associations.)
The main problem I'm facing is the fact that only part of the System's key is used as Primary key in Requirement.
Note: I don't have to abide to a specific legacy database, so the database design can be modified. I am also open to both @EmbeddedId and/or @IdClass solutions. I would prefer compliance with JPA though.
The properties, in my code, need to be mapped through getter/setter, not directly through the fields, but I guess solutions using fields only are fine, as long as the conversion is straight forward.
Thank you.
** EDIT 28/8/2014 **
Consider the following simple test scenario that I am using to test the solutions given:
Software software = new Software(1,10);
System system = new System(2,20);
session.save(software);
session.save(system);
Requirement req = new Requirement();
req.setSoftware(software);
req.setSystem(system);
session.save(req);
You can code Requirement
class as follows:
@Entity
public class Requirement {
@EmbeddedId
private RequirementKey id;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "name", referencedColumnName = "name",
insertable = false, updatable = false),
@JoinColumn(name = "system_version",
referencedColumnName = "version",
insertable = false, updatable = false)
})
private System system;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "id", referencedColumnName = "id",
insertable = false, updatable = false),
@JoinColumn(name = "version",
referencedColumnName = "version",
insertable = false, updatable = false)
})
private Software software;
}
with RequirementKey
:
@Embeddable
public class RequirementKey implements Serializable {
int id;
int version;
String name;
}
I think there is better solution, but I cannot figure out how it may be done.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.