我有一个与这个问题图中概述的情况非常相似的情况:JPA。JoinTable 和两个 JoinColumns,尽管存在不同的问题。
我有三个表:Function
、Group
和Location
。目前,我使用 @JoinTable
在 Location
和 Group
之间设置了一个连接表。它两边都@ManyToMany
,工作得很好。
我正在尝试添加约束,即任何Location
都不应与具有相同Function
的多个Group
相关联。因此,我在 SQL 架构中的联接表中添加了一列用于Function
的列,并在Location
列和Function
列中添加了一个唯一性约束,如下所示:
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;
}
(显然,这些实体还有更多,但我将它们剥离到与此问题相关的部分。
这行不通。当我编写一个简单的测试来创建与Function
关联的Group
关联的Location
时,当我尝试刷新会话以提交事务时,Hibernate给了我这个:
java.lang.ClassCastException: my.package.Group cannot be cast to java.io.Serializable
我认为正在发生的事情是Hibernate变得困惑,举起双手,说"我会序列化它,把它发送到数据库,希望它知道发生了什么。
当我添加implements Serializable
并向Group
添加serialVersionUID
时,我得到这个:
org.hibernate.exception.SQLGrammarException: user lacks privilege or object not found: FUNCTION_ID
在这一点上,我真的不确定如何进行,或者也许我已经在错误的道路上走得太远了。也许我没有正确考虑 SQL,并且有一种更简单的方法来确保这种约束不涉及所有这些荒谬。
编辑:在我的系统中,所涉及的表的DAO没有保存功能。这意味着只要我的约束是在数据库中设置的,我的应用程序就不在乎;它不能插入违反约束的内容,因为它根本无法插入内容。
编辑 2:我最初从未解决所述问题,而是简单地在我的数据库模式中添加了第三列,而不接触 Java 代码,如上面的第一个编辑部分所述。但此后我尝试使用@Embedded
复合键创建一个显式连接表对象,它似乎有效。
您正在尝试创建复合主键。在Hibernate中,您可以使用@Embeddable
注释进行操作。在下面的示例中,您可以找到将组合键用于两个实体的方法。
我相信你可以继续这个例子,并创建你自己的主键版本。
使用复合主键和注释映射多对多: