And*_*ija 5 java hibernate jpa jdbc jakarta-ee
我需要一些看起来不太具体的东西,但无论如何我无法想出漂亮而复杂的解决方案。
假设我有非常简单的 hibernate/jpa 实体:
@Entity(name="entity")
public class Type {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(unique = true, nullable = false)
private String name;
@Column(unique = false, nullable = false)
private boolean defaultType;
}
Run Code Online (Sandbox Code Playgroud)
我需要的是以某种方式注释defaultType字段,以便只有(并且恰好)一个持久化实体将此值设为 true。当新实体以这个defaultType为真被持久化时,旧实体(defaultType = true)必须被改变并且它的defaultType值更改为 false。此外,如果任何实体发生更改(其defaultType更改为 true),则应应用相同的规则。
据我所知,这可以在业务逻辑内部(例如在 DAO 层)、数据库触发器或休眠拦截器或事件(如果有另一种方式,请告诉我)来实现。我尝试过 DAO 解决方案,但这是一种糟糕的解决方案,因为它可以被绕过,而且对于这样简单的操作来说真的很笨拙。数据库触发器不能与 hibernate/jpa 注释一起添加(如果我没记错的话),我不确定如何使用 hibernate 拦截器/事件来实现这个功能。
那么,这个问题的最佳解决方案是什么?
您需要在 JPA 中使用 Callback 方法,例如PreUpdate或PostUpdate,例如:
@Entity
@EntityListeners(com.acme.AlertMonitor.class) // set callback method in another class
public class Account {
Long accountId;
Integer balance;
boolean preferred;
@Id
public Long getAccountId() { ... }
...
public Integer getBalance() { ... }
...
@Transient
public boolean isPreferred() { ... }
...
public void deposit(Integer amount) { ... }
public Integer withdraw(Integer amount) throws NSFException {... }
@PreUpdate // callback method in some class
protected void validateCreate() {
if (getBalance() < MIN_REQUIRED_BALANCE)
throw new AccountException("Insufficient balance to open an
account");
}
@PostUpdate // callback method in some class
protected void adjustPreferredStatus() {
preferred =
(getBalance() >= AccountManager.getPreferredStatusLevel());
}
}
// callback method in another class
public class AlertMonitor {
@PreUpdate // callback method in another class
public void updateAccountAlert(Account acct) {
Alerts.sendMarketingInfo(acct.getAccountId(), acct.getBalance());
}
}
Run Code Online (Sandbox Code Playgroud)
更新:关于你的问题,如果我明白你想要什么,这段代码可能会帮助你:
@Entity(name="entity")
@EntityListeners(com.yourpackage.TypeListner.class)
public class Type {
...
@Column(unique = false, nullable = false)
private boolean defaultType;
}
public class TypeListner {
pivate static Type objectWithTrue = null;
public void init() { // call this method when application is started
List<Type> results = entityManager
.createQuery("from Type", Type.class)
.getResultList();
for(Type type: results) {
if(type.getDefaultType()) {
objectWithTrue = type;
}
}
}
private void changeDefaultType(Type changed) {
if(changed.getDefaultType()) {
if(changed != objectWithTrue && objectWithTrue != null) {
objectWithTrue.setDefaultType(false);
}
objectWithTrue = changed;
}
}
@PostPresist
public void newType(Type changed) {
changeDefaultType(changed);
}
@PostUpdate
public void updateType(Type changed) {
changeDefaultType(changed);
}
@PreRemove
public void removeType(Type changed) {
if(changed.getDefaultType() && objectWithTrue == changed) {
objectWithTrue = null;
}
}
Run Code Online (Sandbox Code Playgroud)
或者
您可以使用 listner @PreUpdate 和 @PrePresist 并每次覆盖所有 Type 对象而不存储任何变量(它的性能不如第一个示例,但更可靠):
@PreUpdate
void updateType(Type changed) {
if(changed.getDefaultType()
List<Type> results = entityManager
.createQuery("from Type", Type.class)
.getResultList();
for(Type type: results) {
if(changed != type && type.getDefaultType()) {
type.setDefaultType(false);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1494 次 |
| 最近记录: |