简体   繁体   English

如何使实体只读?

[英]How to make an Entity read-only?

What is the proper way to make an Entity read-only with JPA ?使用 JPA 使实体只读的正确方法是什么? I wish my database table to never be modified at all programmatically.我希望我的数据库表永远不会以编程方式被修改。

I think I understand that I should lock my objects with LockModeType.READ .我想我明白我应该用LockModeType.READ锁定我的对象。 Is it possible to use an annotation to make my entities directly locked after retrieval from the database ?从数据库中检索后是否可以使用注释使我的实体直接锁定? Or do I have to mess around and override my generic DAO for that specific entity ?或者我是否必须为那个特定实体搞砸并覆盖我的通用 DAO?

In your entity add an EntityListener like this:在您的实体中添加一个EntityListener如下所示:

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

Implement your EntityListener , to throw an exception if any update occurs:实现您的EntityListener ,在发生任何更新时抛出异常:

public class PreventAnyUpdate {

    @PrePersist
    void onPrePersist(Object o) {
        throw new IllegalStateException("JPA is trying to persist an entity of type " + (o == null ? "null" : o.getClass()));
    }

    @PreUpdate
    void onPreUpdate(Object o) {
        throw new IllegalStateException("JPA is trying to update an entity of type " + (o == null ? "null" : o.getClass()));
    }

    @PreRemove
    void onPreRemove(Object o) {
        throw new IllegalStateException("JPA is trying to remove an entity of type " + (o == null ? "null" : o.getClass()));
    }
}

This will create a bullet proof safety net for your entity with JPA lifecycle listeners.这将为具有 JPA 生命周期侦听器的实体创建防弹安全网。

  • PRO: JPA standard - not hibernate specific PRO:JPA 标准 - 不特定于休眠
  • PRO: very safe PRO:非常安全
  • CON: only shows write attempts at runtime . CON:仅显示运行时的写入尝试。 If you want a compile time check, you should not implement setters.如果你想要一个编译时检查,你不应该实现 setter。

A solution is to use field based annotation, to declare your fields as protected and to propose only public getter.一个解决方案是使用基于字段的注释,将您的字段声明为protected并仅建议公共 getter。 Doing so, your objects can not be altered.这样做,您的对象将无法更改。

(This solution is not entity specific, it is just a way to build immutable objects) (此解决方案不是特定于实体的,它只是一种构建不可变对象的方法)

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

If your JPA implementation is hibernate - you could use the hibernate Entity annotation如果您的 JPA 实现是休眠的 - 您可以使用休眠实体注释

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

Obviously this will tie your model to hibernate though.显然,这会将您的模型绑定到休眠状态。

IIRC you could set every field to insertable = false and updatable = false in your @Column annotations, but I'm sure there must be a better method... :) IIRC 您可以在@Column注释中将每个字段设置为insertable = falseupdatable = false ,但我确定必须有更好的方法... :)

I don't suppose this helps?我不认为这有帮助吗?

I think what you are looking for is your entity to be Immutable.我认为你正在寻找的是你的实体是不可变的。 Hibernate supports this; Hibernate 支持这一点; JPA(at least JPA 1.0) does not. JPA(至少 JPA 1.0)没有。 I suppose you can only control this by providing only getters and make sure that the getters return only immutable values.我想你只能通过只提供 getter 来控制这一点,并确保 getter 只返回不可变的值。

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

This is probably going to catch me a downvote because I always get downvoted for suggesting it, but you could use AspectJ in several ways to enforce this:这可能会让我投反对票,因为我总是因为建议而受到反对,但是您可以通过多种方式使用AspectJ来强制执行此操作:

Either automate Mac's solution (make AspectJ inject the @Column annotation):要么自动化 Mac 的解决方案(使 AspectJ 注入@Column注释):

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

Or declare a compiler error for all access to set methods:或者为所有对 set 方法的访问声明一个编译器错误:

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

Downside: you need to add AspectJ compilation to your build, but that's easy if you use ant or maven缺点:您需要将 AspectJ 编译添加到您的构建中,但是如果您使用antmaven ,这很容易

If you are using spring-data or are otherwise using the Repository pattern, don't include any save / update / create / insert / etc methods in the Repository for that particular entity.如果您正在使用 spring-data 或以其他方式使用存储库模式,请不要在该特定实体的存储库中包含任何保存/更新/创建/插入/等方法。 This can be generalized by having a base class / interface for readonly entities, and an updatable one that extends the readonly one for updatable entities.这可以通过具有只读实体的基类/接口和扩展可更新实体的只读实体的可更新基类/接口来概括。 As other posters have pointed out, the setters may also be made non-public to avoid developers accidentally setting values that they are then unable to save.正如其他发布者指出的那样,setter 也可能是非公开的,以避免开发人员意外设置他们无法保存的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM