如何使一个实体只读?

使用JPA只读实体的正确方法是什么? 我希望我的数据库表不能以编程方式修改。

我想我明白我应该用LockModeType.READlocking我的对象。 是否有可能使用注释使我的实体从数据库检索后直接locking? 或者我必须乱七八糟,并重写我的通用DAO的具体实体?

一个解决scheme是使用基于字段的注释,将您的字段声明为protected并只提出公共getter。 这样做,你的对象不能被改变。

(这个解决scheme不是实体特定的,它只是构build不可变对象的一种方式)

如果你的JPA实现是hibernate的 – 你可以使用hibernate的Entity注解

 @org.hibernate.annotations.Entity(mutable = false) 

显然这将把你的模型绑定到hibernate状态。

您可以使用JPA生命周期侦听器为您的实体创build防弹安全网。

  • PRO:JPA标准 – 不是特定于hibernate的
  • PRO:非常安全
  • CON:仅在运行时显示写入尝试。 如果你想编译时间检查,你不应该实现setter。

在你的实体中添加一个EntityListener像这样:

 @Entity @EntityListeners(PreventAnyUpdate.class) public class YourEntity { // ... } 

实现你的EntityListener ,在发生任何更新时抛出一个exception:

 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("..."); } } 

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

Hibernate也有一个org.hibernate.annotations.Immutable注释,你可以把它放在types,方法或字段上。

IIRC你可以设置每个字段在你的@Column注释中updatable = false insertable = falseupdatable = false ,但我相信肯定有一个更好的方法… 🙂

我不认为这有帮助吗?

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

这可能会让我感到厌倦,因为我总是会因为暗示而暗示它,但是您可以通过几种方式来使用AspectJ来执行此操作:

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

 declare @field : (@Entity *) *.* : @Column(insertable=false); 

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

 declare error : execution((@Entity *) *.set*(*) ); 

缺点:您需要将AspectJ编译添加到您的版本,但如果您使用ant或maven ,这很容易