盒装与原始类型作为实体 id

Posted

技术标签:

【中文标题】盒装与原始类型作为实体 id【英文标题】:Boxed vs primitive type as entity id 【发布时间】:2019-01-09 14:20:01 【问题描述】:

在 JPA(Hibernate 实现)中,哪种类型更适合用于实体的 id: 盒装类型(例如Integer)还是未装箱类型(例如int)?

朋友说应该使用 Boxed 类型,因为当你在程序中创建一个新实体时,Hibernate 看到 id 是 null 并理解它应该在数据库中创建一个新行(相反如果 id 不是nullHibernate 可能会更新数据库中的现有行。

但是我的实体的 id 是 int,它运行良好,没有任何错误,我们知道原始实例变量的默认值是 0。所以他说也许hibernate将0视为特殊对象,并假设该对象是一个新对象。

【问题讨论】:

【参考方案1】:

似乎Current Documentation推荐使用盒装类型。

我们建议您在持久类上声明一致命名的标识符属性,并使用可空(即非原始)类型。

【讨论】:

【参考方案2】:

嗯,我们使用非基元,我们有充分的理由这样做。我们的许多字段,例如int/Integer,其绝对商业价值为zero,是完全有效的。例如,考虑一个债务字段 - 如果该字段是 zero,那就更好了,这意味着您没有债务。

问题在于,对于原语,零是默认值 - 因此您可能会不小心忘记通过 setDebt 设置它,因此它可能以您从未使用过的值到达您的数据库打算去那里。出于这个原因,我们使用Integer 和一些不应该为空的验证,例如;但即使我们忘记添加正确的验证,该代码也可能会中断 NullPointerException(最好在测试中),我更喜欢异常而不是数据库中的不一致值。

【讨论】:

这个答案没有解决这个问题。该问题专门询问@Id 字段。您可以通过仅以 1 开始序列(这是 Hibernate 中的默认行为)来避免将 0 作为有效数字。【参考方案3】:

我们可以这样想:

当我们有一个值 x :: Int 时,'x' 是一个计算 评估时将返回 Int 或将 是底部(未定义)。

当程序运行并评估 x 时,假设它评估为 实际 Int(不是底部)。那么在未来任何时候 x 被评估, 而不是重做整个计算,我们只想得到这个值 我们之前计算出来的。

我们要做的就是替换 thunk(计算) 使用 thunk 计算 x,该 thunk 只返回原来的值 之前计算过。

问题是每次你需要在未来得到 x 时,你有 跟随这个指针指向返回值的(平凡的)代码。这 如果您经常需要这些值,就会变得昂贵。

输入未装箱的值。未装箱的值只是那个低级别的值,而不是 包裹在一个thunk里面。这意味着它在某种意义上是严格的 如果你的程序一定会死掉,就不能 undefined。

【讨论】:

【参考方案4】:

对于实体 id,原始(例如 int)和它的包装器(例如 Integer)之间没有区别。根据 JPA 规范,两者都是有效的。 JPA 提供者足够聪明,可以跟踪实体的状态和生命周期。当实体 id 为 0(原始类型)或 NULL(包装器类型)时,如果配置了 id 生成器,JPA 提供程序将为实体生成一个 id。如果 id 是自动生成的,则零不被视为有效的实体 id。

Cmobilecom JPA 测试了这两种情况,效果同样好。当然,没有发现性能差异。

免责声明:我是Cmobilecom JPA 的开发人员,这是一个适用于 Java 和 android 的轻量级 JPA 实现。

【讨论】:

【参考方案5】:

我更喜欢实体模型中的盒装类型,因为这样可以灵活地在泛型中使用盒装类型。 例如,这里的实体模型只能具有扩展为可序列化的类型作为 id。稍后在服务层将很有用,我们可以对主键执行各种操作。

public interface BaseEntity<E extends Serializable> extends Serializable 
  E getId();

实体模型可能是这样的:

@Entity
public class PhoneNumber implements BaseEntity<Long> 
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "PHONE_NUMBER_ID")
  private Long id;

【讨论】:

【参考方案6】:

实体和集合的唯一标识符可以是除二进制、blob 和 clob 之外的任何基本类型。 (也允许使用复合标识符,见下文。)

基本值类型在 org.hibernate.Hibernate 上定义了相应的 Type 常量。例如,Hibernate.STRING 表示字符串类型。

【讨论】:

以上是关于盒装与原始类型作为实体 id的主要内容,如果未能解决你的问题,请参考以下文章

带有 EF 和自动映射器的 OData:无法比较..'。仅支持原始类型、枚举类型和实体类型

始终为 JPA @Id 使用原始对象包装器而不是原始类型?

实体框架,无法创建类型为“XX”的常量值。此上下文仅支持原始类型或枚举类型

实体框架代码优先 CTP5:如何定义非原始类型

ongl(原始类型和包装类型)

java 中的原始类型与原始封装类型