Hibernate使用JoinTable为可选的双向OneToOne生成错误的查询

时间:2016-06-24 15:15:58

标签: java mysql hibernate jpa hibernate-mapping

我有两个实体:

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

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

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

  • raw_device_message id +其他列)
  • tag_detail id +其他列)
  • tag_detail_has_raw_device_message tag_detail_id raw_device_message_id ):此表是具有正确SQL约束和外键的JoinTable,用于强制执行OneToOne关系数据库级别。

我已经映射了我的Java类:

RawDeviceMessage

@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){...}

}

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.id加入tag_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,所以肯定存在错误。

这是一个hibernate错误还是我的映射错误?

1 个答案:

答案 0 :(得分:2)

如果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/