关于休眠:JPA中所使用的referencedColumnName是什么?

What is referencedColumnName used for in JPA?

在JPA中,可以在@JoinColumn, @PrimaryKeyJoinColumn上设置一个名为referencedColumnName的属性,该设置的作用是什么?有人可以举一个很好的示例说明可以在哪里使用它吗?


在那里可以指定另一列作为另一张表的默认ID列,例如考虑以下

1
2
3
4
5
6
7
8
9
10
11
TableA
  id int identity
  tableb_key varchar


TableB
  id int identity
  key varchar unique

// in class for TableA
@JoinColumn(name="tableb_key", referencedColumnName="key")

" referencedColumnName"属性是您要注释的表中正在引用的表中的列的名称。或简而言之:这是目标表中引用的列。想象一下这样的事情:汽车和人。一个人可以拥有多辆汽车,但一辆汽车仅属于一个人(对不起,我不喜欢其他人驾驶我的汽车)。

Table Person
name char(64) primary key
age int

Table Car
car_registration char(32) primary key
car_brand (char 64)
car_model (char64)
owner_name char(64) foreign key references Person(name)

当您实现类时,您将获得类似

1
2
3
4
5
6
7
8
9
10
class Person{
   ...
}

class Car{
    ...
    @ManyToOne
    @JoinColumn([column]name="owner_name", referencedColumnName="name")
    private Person owner;
}

编辑:正如@ searchengine27所评论的那样,columnName作为Java7文档的持久性部分中的字段不存在。我不记得从何处获取此属性,但是我记得使用它,这就是为什么我将其留在示例中的原因。


在referencedColumnName上引用API:

The name of the column referenced by this foreign key
column.

Default (only applies if single join column is being used):
The same name as the primary key column of the referenced table.

问/答

Where this would be used?

当引用表中有复合PK时,则需要指定要引用的列名。


  • name属性指向包含关联的列,即外键的列名
  • referencedColumnName属性指向关联/引用实体中的相关列,即主键的列名

如果引用的实体具有作为PK的单列,则不需要填写referencedColumnName,因为毫无疑问,它引用的是哪一列(即Address单列ID)。

1
2
3
@ManyToOne
@JoinColumn(name="ADDR_ID")
public Address getAddress() { return address; }

但是,如果引用的实体具有跨越多列的PK,则指定@JoinColumn批注的顺序就很重要。在没有指定referencedColumnName的情况下,它可能会起作用,但这很幸运。所以你应该这样映射它:

1
2
3
4
5
6
@ManyToOne
@JoinColumns({
    @JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
    @JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
})
public Address getAddress() { return address; }

ManyToMany

1
2
3
4
5
6
7
8
9
10
@ManyToMany
@JoinTable(
    name="CUST_ADDR",
    joinColumns=
        @JoinColumn(name="CUST_ID"),
    inverseJoinColumns={
        @JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
        @JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
    }
)

现实生活中的例子

Hibernate生成的两个查询具有相同的联接表映射,均未指定引用列。仅@JoinColumn批注的顺序已更改。

1
2
3
4
5
6
7
8
9
10
11
12
/* load collection Client.emails */
select
emails0_.id_client as id1_18_1_,
emails0_.rev as rev18_1_,
emails0_.id_email as id3_1_,
email1_.id_email as id1_6_0_

from client_email emails0_
inner join email email1_ on emails0_.id_email=email1_.id_email

where emails0_.id_client='2' and
emails0_.rev='18'
1
2
3
4
5
6
7
8
9
10
11
12
/* load collection Client.emails */
select
emails0_.rev as rev18_1_,
emails0_.id_client as id2_18_1_,
emails0_.id_email as id3_1_,
email1_.id_email as id1_6_0_

from client_email emails0_
inner join email email1_ on emails0_.id_email=email1_.id_email

where emails0_.rev='2' and
emails0_.id_client='18'

我们正在查询联接表以获取客户的电子邮件。 {2, 18}是客户端的复合ID。列名的顺序由@JoinColumn批注的顺序两个整数的顺序始终相同,可能按休眠顺序排序,这就是为什么需要与联接表列正确对齐的原因,我们不能也不应该依赖于映射顺序。

有趣的是整数的顺序与实体中整数的映射顺序不匹配-在这种情况下,我希望{18, 2}。因此,似乎Hibernate正在对列名称进行排序,然后才在查询中使用它们。如果是这样,那么您将以与不需要referencedColumnName相同的方式订购@JoinColumn,但是我仅出于说明目的而说。

正确填充的referencedColumnName属性将导致完全相同的查询而没有歧义,在我的情况下,这是第二个查询(rev = 2id_client = 18)。


有关具有@OneToMany单向联接的两个表的一般情况的JPA 2.x示例用法,请参见https://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Example_of_a_JPA_2.x_unidirectional_OneToMany_relationship_annotations

WikiBooks JPA文章的屏幕截图:
JPA 2.x单向OneToMany关系数据库的示例