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 = 2
、id_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 一个实体中的两个惰性集合 - 如何运行 JPA 查询以获取实体和只有一个集合