请参考 JPA @Column 注释解释 insertable=false 和 updatable=false

Posted

技术标签:

【中文标题】请参考 JPA @Column 注释解释 insertable=false 和 updatable=false【英文标题】:Please explain about insertable=false and updatable=false in reference to the JPA @Column annotation 【发布时间】:2011-04-17 20:41:26 【问题描述】:

如果一个字段被注解insertable=false, updatable=false,是不是意味着你不能插入值,也不能改变已有的值?为什么要这样做?

@Entity
public class Person 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy="person", cascade=CascadeType.ALL)
    private List<Address> addresses;


@Entity
public class Address 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne
    @JoinColumn(name="ADDRESS_FK")
    @Column(insertable=false, updatable=false)
    private Person person;

【问题讨论】:

【参考方案1】:

当创建/更新引用列的责任不在当前实体中,而是在另一个实体中时,您会这样做.

【讨论】:

您是说在 Person 上使用 updatable=false 时,它​​将在更新地址时禁用 Person.name 的更新(我不同意,因为这是级联的目的)。您还说@Column 定义在其外键(Person)和不是外键时会有所不同(因为没有引用实体来禁用更新)。通过阅读可更新的javadoc,我会说如果它曾经被持久化,它将禁用更改给定地址的Person。你能解释一下吗? 这不是已经被级联选项充分定义了吗?我看到这被用来尝试写入生成的列而不会遇到麻烦。 (例如卷列GENERATED ALWAYS AS (height * width * length) VIRTUAL【参考方案2】:

当您需要在一个实体中多次映射一个字段时,定义 insertable=false, updatable=false 很有用,通常:

使用复合键时 当使用shared primary key 当使用cascaded primary keys

这不是 IMO 的语义问题,而是技术问题。

【讨论】:

我坚信这个答案比公认的要好得多。接受的答案传达了可插入/可更新属性与相关实体的创建/更新有关的感觉,而这些属性背后的真正意图是防止在当前实体中插入/更新列。相关实体的创建/更新由映射注释的级联属性处理。【参考方案3】:

我想在 BalusCPascal Thivent 的答案中添加insertable=false, updatable=false 的另一个常见用法:

考虑一个不是id 而是某种序列号 的列。计算序列号的责任不一定属于应用程序。

例如,序列号从 1000 开始,每增加一个新实体就应该加一。这在数据库中很容易完成,而且非常恰当,在这种情况下,这些配置是有意义的。

【讨论】:

JPA 也支持序列,因此您也可以使用 JPA 注释定义序列。【参考方案4】:

另一个示例是在“created_on”列上,您希望在该列中让数据库处理创建日期

【讨论】:

Hibernate 是否应该基于 updatable=false 注释阻止更新?在我的 JPA 存储库测试中,带有此注释的 created_on 列可以毫无怨言地接受更新。 @chrisinmtown Eclipselink 根本不会在 sql 中包含该列。我希望它与 Hibernate 相同 其实这是我的回应【参考方案5】:

根据 Javax 的持久化文档:

该列是否包含在持久性提供程序生成的 SQL UPDATE 语句中。

最好从官方文档here了解。

【讨论】:

【参考方案6】:

除了前面的答案之外,insertable=false, updatable=false 的一个常见用途是节省冗余的数据库查询,从而提高性能。

想象一下有一个 Client 类,它有一个 Parent 实体。如果您只想检查客户是否有父级,您只需检查其parent_id 列中是否存在值。无需让 Hibernate 获取父实体,可能还有它的所有其他关联,从而导致额外数量的查询:

public class Client 
    @ManyToOne(cascade = CascadeType.MERGE, CascadeType.PERSIST, fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    private Parent parent;

    @Column(name = "parent_id", insertable = false, updatable = false)
    private UUID parentId;

通过上述设置,parentId 字段将简单地获取存储在 parent_id 列中的任何值,该列仅由父实体编辑/更新。

【讨论】:

【参考方案7】:

我认为这只是意味着:

该列是否包含在持久性提供程序生成的 SQL INSERT 语句中。

参考:https://www.objectdb.com/api/java/jpa/Column

【讨论】:

【参考方案8】:

另一个原因可能是您的属性映射到视图的列(例如,您的休眠实体是表和视图的融合)。因此,可以插入(也不能更新)您的列是没有意义的。

@Entity
@Table(name = "THE_VIEW")
@SecondaryTable(name = "THE_TABLE", pkJoinColumns = @PrimaryKeyJoinColumn(name = "THE_ID"))
public class MyEntity 

    @Id
    @Column(name = "THE_ID")
    private Integer id;

    @Column(name = "VIEW_COLUMN", updatable = false, insertable = false)
    private String viewColumn

    @Column(name = "TABLE_COLUMN", table = "THE_TABLE")
    private String tableColumn;

(我这里不讨论可更新视图)

【讨论】:

以上是关于请参考 JPA @Column 注释解释 insertable=false 和 updatable=false的主要内容,如果未能解决你的问题,请参考以下文章

在 @Column JPA 注释上设置长度属性时有啥作用?

通过使用 Jooq 和 JPA 的 @Column 注释来验证字段长度

Java 持久性/JPA:@Column 与 @Basic

BigDecimal 的 JPA @Size 注释

JoinColumn解释

@JoinColumn解释