如何使一个实体只读?
使用JPA只读实体的正确方法是什么? 我希望我的数据库表不能以编程方式修改。
我想我明白我应该用LockModeType.READ
locking我的对象。 是否有可能使用注释使我的实体从数据库检索后直接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 = false
和updatable = false
,但我相信肯定有一个更好的方法… 🙂
我不认为这有帮助吗?
Eclipselink实现还为您提供实体级别的@ReadOnly
注释
这可能会让我感到厌倦,因为我总是会因为暗示而暗示它,但是您可以通过几种方式来使用AspectJ来执行此操作:
要么自动化Mac的解决scheme(使AspectJ注入@Column
注释):
declare @field : (@Entity *) *.* : @Column(insertable=false);
或者为所有对set方法的访问声明一个编译器错误:
declare error : execution((@Entity *) *.set*(*) );
缺点:您需要将AspectJ编译添加到您的版本,但如果您使用ant或maven ,这很容易