JPA @JoinTable - 三个ID列

时间:2013-02-15 17:06:46

标签: java hibernate unique-constraint multiple-columns jointable

我的情况与此问题图中概述的情况非常相似:JPA. JoinTable and two JoinColumns,但有不同的问题。

我有三个表:FunctionGroupLocation。目前,我使用LocationGroup@JoinTable之间设置了联接表。双方都是@ManyToMany,并且完美无缺。

我正在尝试添加约束,Location不应与具有相同Group的多个Function相关联。所以我在我的SQL模式中为Function添加了一个列到我的连接表中,并在LocationFunction列中添加了唯一性约束,如下所示:

create table function_table (
  id varchar(50),
  primary key(id)
);

create table group_table (
  id varchar(50),
  function_id varchar(50) not null,
  primary key(id)
);

alter table group_table add constraint FK_TO_FUNCTION foreign key (function_id) references function_table;

create table location_table (
  id varchar(50),
  primary key(id)
);

create table group_location_join (
  location_id varchar(50) not null,
  group_id varchar(50) not null,
  function_id varchar(50) not null,
  primary key(location_id, group_id, function_id),
  unique(location_id, function_id)
);

alter table group_location_join add constraint FK_TO_LOCATION foreign key (location_id) references location_table;
alter table group_location_join add constraint FK_TO_GROUP foreign key (group_id) references group_table;
alter table group_location_join add constraint FK_TO_FUNCTION foreign key (function_id) references function_table;

然后我尝试在我的模型实体中设置以下内容:

@Entity
@Table(name = "function_table")
public class Function {
  @Id
  @Column(name = "id", length = 50)
  private String id;
}

@Entity
@Table(name = "group_table")
public class Group {
  @Id
  @Column(name = "id", length = 50)
  private String id;

  @ManyToOne
  @JoinColumn(name = "function_id", referencedColumnName = "id", nullable = false)
  private Function function;

  @ManyToMany
  @JoinTable(name = "group_location_join",
    joinColumns = {@JoinColumn(name = "group_id", referencedColumnName = "id"),
                   @JoinColumn(name = "function_id", referencedColumnName = "function_id")},
    inverseJoinColumns = @JoinColumn(name="location_id", referencedColumnName = "id"))
  private Set<Location> locations;
}

@Entity
@Table(name = "location_table")
public class Location {
  @Id
  @Column(name = "id", length = 50)
  private String id;

  @ManyToMany
  @JoinTable(name = "group_location_join",
    joinColumns = @JoinColumn(name="location_id", referencedColumnName = "id")
    inverseJoinColumns = {@JoinColumn(name = "group_id", referencedColumnName = "id"),
                   @JoinColumn(name = "function_id", referencedColumnName = "function_id")})
  private Set<Group> groups;
}

(显然,这些实体还有更多,但我只将它们剥离到与此问题相关的部分。)

这不起作用。当我编写一个简单的测试来创建与Location关联的Group Function时,我尝试刷新会话以提交事务,Hibernate给了我这个:

java.lang.ClassCastException: my.package.Group cannot be cast to java.io.Serializable

我认为正在发生的事情是Hibernate变得困惑,扯下手,并说“我只是序列化它,将它发送到数据库,并希望它知道发生了什么。”

当我添加implements Serializable并向serialVersionUID添加Group时,我就明白了:

org.hibernate.exception.SQLGrammarException: user lacks privilege or object not found: FUNCTION_ID

我不确定如何继续这一点,或者我是否已经走错了路。也许我没有正确地考虑SQL,并且有一种更容易的方法来确保这种约束并不涉及所有这些荒谬。

编辑:在我的系统中,所涉及的表的DAO没有保存功能。这意味着只要我的约束在数据库中设置,我的应用程序就不在乎;它不能插入违反约束的东西,因为它根本无法插入东西。

编辑2:我从来没有解决过规定的问题,只是在我的数据库架构中添加了第三列而没有触及Java代码,如我的第一个编辑以上部分。但是我已经尝试使用@Embedded复合键创建一个显式连接表对象,它似乎有效。

1 个答案:

答案 0 :(得分:1)

您正在尝试创建复合主键。在Hibernate中,您可以使用@Embeddable注释来完成它。在下面的示例中,您可以找到为两个实体使用复合键的方法。

我相信您可以继续使用此示例并创建自己的主键版本。

Mapping ManyToMany with composite Primary key and Annotation: