JPA 中的 referencedColumnName 用于啥?

Posted

技术标签:

【中文标题】JPA 中的 referencedColumnName 用于啥?【英文标题】:What is referencedColumnName used for in JPA?JPA 中的 referencedColumnName 用于什么? 【发布时间】:2012-06-29 23:15:10 【问题描述】:

在 JPA 中有一个名为 referencedColumnName 的属性可以在 @JoinColumn, @PrimaryKeyJoinColumn 上设置这个设置背后的想法是什么,有人可以举一个很好的例子来说明它可以在哪里使用吗?

【问题讨论】:

【参考方案1】:

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

TableA
  id int identity
  tableb_key varchar


TableB
  id int identity
  key varchar unique

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

【讨论】:

【参考方案2】:

“referencedColumnName”属性是表中列的名称,您正在使用您正在注释的列进行引用。或者简而言之:它是目标表中引用的列。想象这样的事情:汽车和人。一个人可以有很多辆车,但一辆车只属于一个人(对不起,我不喜欢别人开我的车)。

表人 name char(64) 主键 年龄说明

桌车 car_registration char(32) 主键 car_brand (char 64) car_model (char64) owner_name char(64) 外键引用 Person(name)

当你实现类时,你会得到类似的东西

class Person
   ...


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

编辑: 正如@searchengine27 所评论的,columnName 在 Java7 文档的持久性部分中不作为字段存在。我不记得我是从哪里得到这个属性的,但我记得使用过它,这就是我将它留在我的示例中的原因。

【讨论】:

eh...columnName 不是annotation 的字段... @searchengine27,这个答案来自 7 多年前...根据文档,看起来columnName 在 java7 规范和 java6 中都没有定义(这是我在回答时使用的版本这)。所以看起来你是对的 此外,除了极少数例外,Java(和 JavaEE)是相当向后兼容的。事物通常被弃用而不是删除。所以我通常不会直接跳到“它已被删除”。甚至 JavaSE 中的泛型也是在 Java SE 5 中发布的,并且考虑到了向后兼容性,这让所有对类型擦除一无所知的人都感到沮丧和困惑。【参考方案3】:

引用API on referencedColumnName:

此外键引用的列的名称 列。

默认(仅在使用单个连接列时适用): 与被引用表的主键列同名。

问/答

这将在哪里使用?

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

【讨论】:

或者,在@ManyToMany映射中,当你有一个中间表时。【参考方案4】: name属性指向包含关联的列,即外键的列名 referencedColumnName属性指向关联/引用实体中的相关列,即主键的列名

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

@ManyToOne
@JoinColumn(name="ADDR_ID")
public Address getAddress()  return address; 

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

@ManyToOne
@JoinColumns(
    @JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
    @JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
)
public Address getAddress()  return address; 

或者在ManyToMany的情况下:

@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 注释的顺序。

/* 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'
/* 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)。

【讨论】:

【参考方案5】:

对于两个表的一般情况的 JPA 2.x 示例用法,@OneToMany 单向连接请参阅https://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Example_of_a_JPA_2.x_unidirectional_OneToMany_relationship_annotations

此 WikiBooks JPA 文章的屏幕截图: Example of a JPA 2.x unidirectional OneToMany relationship database

【讨论】:

以上是关于JPA 中的 referencedColumnName 用于啥?的主要内容,如果未能解决你的问题,请参考以下文章

jpa中的重置序列

WildFly 中的 JPA 共享缓存/二级缓存

JPA 一个实体中的两个惰性集合 - 如何运行 JPA 查询以获取实体和只有一个集合

JPA 中的 @Any 等价于啥?

Apache Felix 中的 JPA / Hibernate 集成

JPA 中的 nativeQuery