Java JPA/Hibernate:如何将复合外键与部分主键关联

Java JPA/Hibernate:如何将复合外键与部分主键关联,java,hibernate,jpa,Java,Hibernate,Jpa,我有两个表,每个表都有一个复合键: 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) ); 现在,我需要一个关联,在这里我可以表达“软件对它可以运

我有两个表,每个表都有一个复合键:

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)
);
现在,我需要一个关联,在这里我可以表达“软件对它可以运行的系统版本有最低要求”的概念。下表在DB级别执行此操作:

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)
)
请注意,需求有三个字段作为主键。如果我将所有四个都设置为主,那么我可以表示一个软件的多个需求(即OpenLib v1.2依赖于Ubuntu 13.04和Ubuntu 13.10),而一个软件对于给定的操作系统只能有一个需求(在本例中,OpenLib v1.2依赖于Ubuntu 13.04)

如何将其映射到JPA/Hibernate@Entity对象(使用注释)?(包括相关的一通/多通协会。)

我面临的主要问题是,在需求中,只有部分系统密钥被用作主键

注意:我不必遵守特定的遗留数据库,因此可以修改数据库设计。 我也对@EmbeddedId和/或@IdClass解决方案持开放态度。不过,我更愿意遵守JPA

在我的代码中,属性需要通过getter/setter映射,而不是直接通过字段映射,但我想只使用字段的解决方案是可以的,只要转换是直接进行的

多谢各位

**编辑2014年8月28日**

考虑以下我用来测试给定解决方案的简单测试场景:

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);

您可以按如下方式对
需求
类进行编码:

@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;

}
使用
RequirementKey

@Embeddable
public class RequirementKey implements Serializable {
    int id;
    int version;
    String name;
}

我认为有更好的解决方案,但我不知道如何实现。

不起作用:系统变量和软件变量都引用数据库中的同一列“版本”。请注意,需求中有4列,两个“版本”是不同的。@Filippo那么,您的观点是在
需求中有四列还是三列?我上面的代码假设您想要有三列(每列都属于需求PK),并且它在Hibernate 4.3.5和JPA 2.1.4下工作。三个是PK,一个不是。在这四列中,两列为FK,表示软件,两列为FK,表示系统。名为system_version的列不是PK的一部分,但它在系统中(与软件_version不同)。查看数据库布局的SQL语句。@Filippo查看一下更新,现在它生成了
Requirement
表,表中有四列,其中三列为PK,我们将尝试。尽管我对system\u版本联接列定义中的“insertable=false,Updateable=false”感到困惑。hibernate会插入值吗?恐怕这栏会空着。。。