如何使实体成为只读?

glm*_*ndr 67 java jpa

使用JPA使实体成为只读的正确方法是什么?我希望我的数据库表永远不会以编程方式进行修改.

我想我明白我应该锁定我的对象LockModeType.READ.从数据库中检索后,是否可以使用注释使我的实体直接锁定?或者我是否必须乱用并覆盖我的特定实体的通用DAO?

Nic*_*las 45

解决方案是使用基于字段的注释,将您的字段声明为protected仅提议公共getter.这样做,您的对象无法更改.

(此解决方案不是特定于实体的,它只是构建不可变对象的一种方法)

  • 你忘了:"并确保getter只返回不可变的值".例如收集字段 (17认同)
  • 你应该使用private而不是protected.使其受到保护您仍然可以通过同一个包中的其他类访问该属性.拇指实例变量规则始终是私有的. (4认同)
  • 使用这种方法,您仍然可以添加新实体(插入) (4认同)

sla*_*dan 35

您可以使用JPA生命周期监听器为您的实体创建防弹安全网.

  • PRO:JPA标准 - 不是特定于hibernate的
  • PRO:非常安全
  • CON:仅显示运行时的写入尝试.如果要进行编译时检查,则不应实现setter.

在您的实体中添加EntityListener如下:

@Entity
@EntityListeners(PreventAnyUpdate.class)
public class YourEntity {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

实现你的EntityListener,如果发生任何更新,则抛出异常:

public class PreventAnyUpdate {

    @PrePersist
    void onPrePersist(Object o) {
        throw new RuntimeException("...");
    }

    @PreUpdate
    void onPreUpdate(Object o) {
        throw new RuntimeException("...");
    }

    @PreRemove
    void onPreRemove(Object o) {
        throw new RuntimeException("...");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 几年后我看到了这一点,它仍然是一个很好的解决方案。:) (5认同)

And*_*w B 21

如果你的JPA实现是休眠的 - 你可以使用hibernate实体注释

@org.hibernate.annotations.Entity(mutable = false)
Run Code Online (Sandbox Code Playgroud)

显然,这会将你的模型与休眠联系起来.

  • 实体在jpa2 hibernate中已弃用,而是使用@Immutable (51认同)

Tob*_*san 19

Hibernate还有一个org.hibernate.annotations.Immutable可以放在类型,方法或字段上的注释.

  • 小心`@ Immutable`.这不是很有帮助.如果你尝试更新,它不会出错:它只会**默默地失败**.从Hibernate的文档:"将忽略对不可变实体的更新,但不会抛出任何异常". (9认同)
  • 您还可以使用 @Immutable 注释实体。在我们的例子中,我们需要静默失败,因为我们想要更新某些实体而不是其他实体,而应该使用存储过程来更新。 (2认同)

DaT*_*oop 13

我认为你所寻找的是你的实体是永恒的.Hibernate支持这个; JPA(至少JPA 1.0)没有.我想你只能通过提供getter来控制它,并确保getter只返回不可变的值.


Mac*_*Mac 11

IIRC你可以每字段设置为insertable = falseupdatable = false您的@Column注解,但我敢肯定,必须有一个更好的方法... :)

我不认为这有帮助吗?


Pau*_*Pau 10

Eclipselink实现还为您提供@ReadOnly实体级别的注释


Sea*_*oyd 6

这可能会让我失望,因为我总是倾向于建议它,但您可以通过多种方式使用AspectJ来强制执行此操作:

要么自动化Mac的解决方案(使AspectJ注入@Column注释):

declare @field : (@Entity *) *.* : @Column(insertable=false);
Run Code Online (Sandbox Code Playgroud)

或者为所有对set方法的访问声明编译器错误:

declare error : execution((@Entity *) *.set*(*) );
Run Code Online (Sandbox Code Playgroud)

缺点:您需要在构建中添加AspectJ编译,但如果您使用antmaven则很容易

  • 允许框架使用它们 编译器错误仅针对本地代码,JPA 提供程序的代码通常不会使用切面进行编织 (2认同)

小智 5

如果您正在使用 spring-data 或以其他方式使用存储库模式,请不要在该特定实体的存储库中包含任何保存/更新/创建/插入/等方法。这可以通过具有只读实体的基类/接口和扩展可更新实体的只读实体的可更新基类/接口来概括。正如其他发布者指出的那样,setter 也可能是非公开的,以避免开发人员意外设置他们无法保存的值。