JPA 可嵌入 PK 和可为空的字段

Posted

技术标签:

【中文标题】JPA 可嵌入 PK 和可为空的字段【英文标题】:JPA Embeddeble PK and nullable field 【发布时间】:2014-05-23 09:03:27 【问题描述】:

我有一个名为“属性”的表,它有 3 个字段的 PK 可以为空。在这种情况下 Style_no 不为空,但 item_no 和 size_no 为空。

是否可以有一个Embeddeble PK,其中字段可以为空?

@Entity
@Table(name="ATTRIBUTE")
public class Attribute 

    @EmbeddedId
    private AttributePK attrPK;
    ...

    @Embeddable
    public static class AttributePK implements Serializable

        private static final long serialVersionUID = -2976341677484364274L;

        @Column(name="STYLE_NO", nullable=true)
        protected String styleNo;

        @Column(name="ITEM_NO", nullable=true)
        protected String itemNo;

        @Column(name="SIZE_NO", nullable=true)
        protected String sizeNo;
    ...

当我尝试引用一个字段时,例如style_no 结果数量为0。

@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, orphanRemoval=true, mappedBy="attrPK.styleNo")
@MapKey(name="attrPK.name")
public Map<String,Attribute> attributesX;

@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name="STYLE_NO", referencedColumnName="STYLE_NO")
private List<Attribute> attributes;

当我将 item_no 和 size_no 作为 pk 删除时,我收到了有效的结果。

编辑: 为了让我的问题更具体。是否允许根据 JPA 指南或“常识”对 EmbeddebedId 使用可为空的字段?如果没有,我需要添加哪些注释或逻辑才能使其在不添加另一个 PK 的情况下工作? 一旦用值填充 PK 中的可为空字段。结果是正确的。

非常感谢!

【问题讨论】:

【参考方案1】:

既然you must not use null in your PK,这就是你应该做的:

    添加surrogate primary key。

    你仍然可以通过二分索引(在 PostgreSQL 中)实现唯一性约束和默认 PK 索引:

    在 my_table (Style_no, item_no, size_no) WHERE (item_no IS NOT NULL AND size_no IS NOT NULL) 上创建唯一索引 style_item_size_idx;

【讨论】:

谢谢,但是,我明确地询问了一个没有添加另一个 id 的解决方案 - “..它可以在不添加另一个 PK 的情况下工作..”。 我明白,只是这是您需要注意的数据库限制。 当然,我上面的例子只是为了找出 Hibernate 作为一个额外的层,是否可以避免这种特定于 DB 的边界。没有真正的用例。 these reasons 总是选择 Hibernate,否则我只会使用具有强大查询能力的 JOOQ。【参考方案2】:

看看here 似乎, (NULL == NULL) -> false 的答案与您的问题有关。

【讨论】:

谢谢你的链接。但是正如下面的 cmets 正确提到的那样,它并不令人满意。例如。从 JPA 开始,它不允许在可以为空的字段上使用 Id。但我找不到 EmbeddedId 的相同限制。我所需要的是,如果有一种解决方法,而不添加另一个人工 ID 或指向源的链接,该链接表明 EmbeddedId 中的可为空字段是不允许的。【参考方案3】:

通常复合 pk 不允许在数据库中有空值。

技术上我们会说:为什么不呢,null 也可以是一个值。

DB-Analyst 会问:好的,如果我排序 1,2,3,4,null,5。你说null是在1之前还是5之后?

因此 PostgreSQL、Oracle、mysql 将不支持复合主键中的空值。

【讨论】:

1) 对于订单,我会说数据库可以自行决定。从技术上讲,它在任何地方定义都很重要。 2) 是的,不允许 PK 约束。对于 UNIQUE 约束,它是允许的,但它仍然不适用于休眠。 @MortalFool 你是对的,我添加了最后一个单词:primary 以清除键和主键之间的区别。【参考方案4】:

JPA 准则或“常识”不允许为 EmbeddebedId 使用可为空的字段?如果没有,我需要添加哪些注释或逻辑才能使其在不添加另一个 PK 的情况下工作?

答案如下

@EmbeddedId
private AttributePK attrPK;

不允许主键为空。

所以要做到这一点,请使用下面的另一个注释

@IdClass(AttributePK.class)
 private AttributePK attrPK;

【讨论】:

谢谢,我明天试试验证。 IdClass 有一个@Target(ElementType.TYPE),你怎么能把它放在一个字段上???

以上是关于JPA 可嵌入 PK 和可为空的字段的主要内容,如果未能解决你的问题,请参考以下文章

XmlCodeExporter 和可为空的类型

XmlSerializer 和可为空的属性

XmlConvert 和可为空的结果?

代码首先为必填字段生成可为空的列

Laravel 验证中有时和可为空的区别

尝试解析可为空的字段时出现 AvroTypeException