【问题标题】:Hibernate generates wrong query for optional bi-directional OneToOne with JoinTableHibernate 使用 JoinTable 为可选的双向 OneToOne 生成错误的查询
【发布时间】:2016-10-27 06:29:37
【问题描述】:

我有两个实体:

  • RawDeviceMessage,表示来自设备的原始消息
  • TagDetail 表示解析后的消息

TagDetail 可能会或可能不会与 RawDeviceMessage 相关联,因为它可以直接创建而无需解析原始消息。因此,我在 RawDeviceMessage 和 TagDetail 之间有一个可选的双向 OneToOne 关系。

在数据库中我有以下表格:

  • raw_device_messageid + 其他列)
  • tag_detailid + 其他列)
  • tag_detail_has_raw_device_message (tag_detail_id , raw_device_message_id) :此表是一个 JoinTable,具有适当的 SQL 约束和外键以在数据库级别强制执行 OneToOne 关系.

我已经像这样映射了我的 Java 类:

原始设备消息

@Entity
@Table(name = "raw_device_message")
public class RawDeviceMessage implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", unique = true, updatable = false, nullable = false)
    private Long id;

    @OneToOne(mappedBy = "rawDeviceMessage", fetch = FetchType.LAZY)
    private TagDetail tagDetail;

    public RawDeviceMessage(){}

    public Long getId(){...}
    public void setId(final Long id){...}
    public TagDetail getTagDetail(){...}
    public RawDeviceMessage setTagDetail(TagDetail tagDetail){...}

}

标签详情

@Entity
@Table(name = "tag_detail")
public class TagDetail implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", unique = true, updatable = false, nullable = false)
    private Long id;

    @OneToOne(fetch = FetchType.EAGER, cascade = { CascadeType.REFRESH, CascadeType.MERGE })
    @JoinTable(
        name="tag_detail_has_raw_device_message",
        joinColumns=@JoinColumn(name="tag_detail_id"),
        inverseJoinColumns=@JoinColumn(name="raw_device_message_id"))
    private RawDeviceMessage rawDeviceMessage;

    public TagDetail() {}

    public Long getId(){...}
    public void setId(final Long id){...}
    public RawDeviceMessage getRawDeviceMessage(){...}
    public void setRawDeviceMessage(RawDeviceMessage rawDeviceMessage){...}
}

问题

我的问题是,在 RawDeviceMessage 资源上执行 find all 时,Hibernate 会生成错误的 SQL 查询:

SELECT rawdevicem0_.id AS id1_15_,
       rawdevicem0_2_.tag_detail_id AS tag_deta0_37_,
FROM raw_device_message rawdevicem0_
LEFT OUTER JOIN tag_detail_has_raw_device_message rawdevicem0_2_ ON rawdevicem0_.id=rawdevicem0_2_.tag_detail_id
CROSS JOIN tag_detail tagdetail1_
LEFT OUTER JOIN tag_detail_has_raw_device_message tagdetail1_1_ ON tagdetail1_.id=tagdetail1_1_.tag_detail_id
WHERE rawdevicem0_2_.tag_detail_id=tagdetail1_.id
ORDER BY rawdevicem0_.id ASC

如您所见,在第一个LEFT OUTER JOIN中,连接条件为rawdevicem0_.id=rawdevicem0_2_.tag_detail_id

它试图将 raw_device_message.idtag_detail_has_raw_device_message.tag_detail_id 连接起来,这没有任何意义,并且会弄乱所有结果。

连接条件应该是rawdevicem0_.id=rawdevicem0_2_.raw_device_message_id 此条件将正确地将 raw_device_message.idtag_detail_has_raw_device_message.raw_device_message_id 连接起来

我已经缩短了hibernate生成的查询以删除所有不相关的字段,但是在生成的查询中没有raw_device_message_id列,所以肯定有问题。

这是休眠错误还是我的映射错误?

【问题讨论】:

  • 请发布您的findAll 查询,乍一看我会说您在那里做错了。
  • @DraganBozanovic 我正在使用 Spring 的 JpaRepository List<T> findAll(); 所以我自己不写任何查询。
  • 你使用的是什么版本的休眠?你用的是什么数据库?我将您的实体复制到 postgres 数据库中并告诉它自动导出模式。对我来说,FK 是在数据库中正确创建的,并且生成的查询也可以按预期工作。我无法重现您所描述的行为。
  • 我使用的是 Hibernate 5.1.0.Final 和 MySQL 5.7。我不知道为什么我有这个错误。我最终删除了从 RawDeviceMessage 到 TagDetail 的双向关系以“解决”我的问题。

标签: java mysql hibernate jpa hibernate-mapping


【解决方案1】:

如果tag_detail_has_raw_device_message表的目的只是链接两个表,那么你可以删除它。您可以仅使用两张桌子进行一对一。 更多细节在这里 - Setting up a One To ManyJoins Against a Bridge Table using JPA

但是,如果您想要一个中间映射表,因为它包含该关系的一些附加信息,那么这里有更多详细信息。

http://what-when-how.com/hibernate/advanced-entity-association-mappings-hibernate/

【讨论】:

  • 我需要一个连接表,因为我的 OneToOne 关联是可选的。我不想让 tag_detail 表中的一列填充一半的 NULL 值。我已经阅读了您第二个链接中的文档。在“您可以将可选的一对一关联映射到带有注释的中间连接表”这句话下,正是我正在使用的映射。但是,正如我发现的那样,它不起作用,因为生成的 SQL 是错误的。
  • 是的。但是那个例子没有描述另一面(Item 到 Shipment_item 的映射,它只是显示了 Shipmment 到 Shipment_item 的映射)。另外,我很好奇你是怎么得到这个 SQL 的,因为 RawDeviceMessage 有 TagDevice 的延迟加载,所以当我用 findAll() 尝试相同的代码时,我打印了一个更简单的 SQL。实体映射/类是否正确?
  • 我只是将休眠日志记录设置为跟踪并生成了 sql。 Hibernate 获取了该关系,因为我在 JPA 标准规范中访问它。
猜你喜欢
  • 1970-01-01
  • 2021-01-31
  • 2021-07-14
  • 2013-08-19
  • 2017-09-18
  • 2017-12-25
  • 2013-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多