jpa hibernate @OneToOne @JoinColumn referencedColumnName 被忽略

Posted

技术标签:

【中文标题】jpa hibernate @OneToOne @JoinColumn referencedColumnName 被忽略【英文标题】:jpa hibernate @OneToOne @JoinColumn referencedColumnName ignored 【发布时间】:2016-08-31 02:01:32 【问题描述】:

我在对与另一个具有一对一关系的实体执行 jpql 查询时遇到意外行为。关键是,关系是从根实体的主键到目标实体的一个字段,而不是ID。

示例如下:

// root entity
@Entity
@Table(name = "PERSON")

public class Person 

    @Id
    @Column(name = "PERSON_ID")
    private long id;

    private String name;

    @OneToOne(optional = false)
    @JoinColumn(name = "PERSON_ID", referencedColumnName = "PERSON_ID", insertable = false, updatable = false, unique = true)
    private Address mainAddress;
    ...

// referenced entity
@Entity
@Table(name = "ADDRESS")
public class Address 

    @Id
    @Column(name = "ADDRESS_ID")
    private long id;

    @Column(name = "PERSON_ID")
    private long personId;
    ...

以下jpql查询:

select p from Person p left join fetch p.mainAddress

产生以下 ORACLE SQL 查询:

SELECT ... FROM PERSON p LEFT OUTER JOIN ADDRESS a ON p.PERSON_ID = a.ADDRESS_ID

虽然我期待:

SELECT ... FROM PERSON p LEFT OUTER JOIN ADDRESS a ON p.PERSON_ID = a.PERSON_ID

基本上 referencedColumnName = "PERSON_ID" 属性的属性被忽略,并且在主键上执行连接。

谁能解释一下为什么?

【问题讨论】:

我通过映射反向关系和使用mappedBy属性解决了。这样,ORM 就知道哪个是连接列。谢谢@Alan Hay 你找到解决办法了吗? 【参考方案1】:

@OneToOne 按原样映射后,外键将位于 Person 表中,即。 Person 表(如果您没有在 @JoinColumn 注释中指定 person_id)应该有一个 FK 列“address_id”。

形成您期望生成的 SQL 的样子,您似乎希望 FK 在地址表中,即地址有一个 FK 列 person_id。您可以通过以下方式做到这一点:

@Entity
@Table(name = "PERSON")

public class Person 

    @Id
    @Column(name = "PERSON_ID")
    private long id;

    private String name;

    @OneToOne(mappedBy = "person")
    private Address mainAddress;




@Entity
@Table(name = "ADDRESS")
public class Address 

    @Id
    @Column(name = "ADDRESS_ID")
    private long id;

    @OneToOne(optional = false)
    @JoinColumn(name = "PERSON_ID", insertable = false, updatable = false, unique = true)
    private Person person;


【讨论】:

你在句子中说人会address_id 但在示例地址中会有它。 我要说的是:使用@OneToOne 按原样映射,外键将在 Person 表中。注意重点,这是重要的部分。【参考方案2】:

我认为,@OneToOne 映射的@JoinColumn 表示持久化表中的连接列,其中指定了@JoinColumnPerson,(与@OneToMany 不同)。

所以使用更简单清晰的映射

@Entity
@Table(name = "persons")
public class Person 

    @Id
    @Column(name = "f_id")
    private Long id;

    @Column(name = "f_name")
    private String name;

    @OneToOne(mappedBy = "person", optional = false)
    private Address mainAddress;



@Entity
@Table(name = "addreses")
public class Address 

    @Id
    @Column(name = "f_id")
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "fk_person")
    private Person person; 


【讨论】:

以上是关于jpa hibernate @OneToOne @JoinColumn referencedColumnName 被忽略的主要内容,如果未能解决你的问题,请参考以下文章

在 Hibernate / JPA 2.1 中延迟加载的 @OneToOne 映射不起作用?

hibernate/jpa double OneToOne 与一个实体的双向关系

jpa hibernate @OneToOne @JoinColumn referencedColumnName 被忽略

如何使用 BooleanBuilder (QueryDSL) 为可选的 OnetoOne JPA/Hibernate 关系建模谓词?

休眠 | Spring Data JPA | @OneToOne

如何处理 JPA @OneToOne 映射中的“孤立”行