如下所述的链接作者:
我目前正在开发一个Seam应用程序,需要在数据库中进行软删除。在右侧,您可以看到我的数据库图表的一部分,其中包含CUSTOMER
和APP_USER
表。这只是一个简单的一对多关系,但需要注意的重要事项是每个表中的“DELETED”字段。这是将用于跟踪软删除的字段。如果该字段包含“1”,则表示记录已被删除,如果包含“0”,则表示记录尚未被删除。
![enter image description here](https://istack.dev59.com/mMBpA.webp)
在有像Hibernate这样的ORM之前,我需要使用SQL来跟踪和设置此标志。虽然这并不是很难做到,但谁想写一堆样板代码来跟踪记录是否已被删除呢?这就是Hibernate和注释发挥作用的地方。
下面是由Hibernate使用seamgen生成的2个实体类。为了清晰起见,我省略了部分代码。
Customer.java
@Entity
@Table(name = "CUSTOMER")
@SQLDelete(sql="UPDATE customer SET deleted = '1' WHERE id = ?")
@Where(clause="deleted <> '1'")
public class Customer implements java.io.Serializable {
private long id;
private Billing billing;
private String name;
private String address;
private String zipCode;
private String city;
private String state;
private String notes;
private char enabled;
private char deleted;
private Set appUsers = new HashSet(0);
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "customer")
@Where(clause = "deleted <> '1'")
public Set getAppUsers() {
return this.appUsers;
}
public void setAppUsers(Set appUsers) {
this.appUsers = appUsers;
}
}
AppUser.java
@Entity
@Table(name = "APP_USER")
@SQLDelete(sql="UPDATE app_user SET deleted = '1' WHERE id = ?")
@Where(clause="deleted <> '1'")
public class AppUser implements java.io.Serializable {
private long id;
private Customer customer;
private AppRole appRole;
private char enabled;
private String username;
private String appPassword;
private Date expirationDate;
private String firstName;
private String lastName;
private String email;
private String phone;
private String fax;
private char deleted;
private Set persons = new HashSet(0);
}
以下2个步骤就是我实现软删除所需的全部操作。
- 添加
@SQLDelete
注释,覆盖该实体的默认Hibernate删除方式。
- 添加
@Where
注释以过滤查询并仅返回未被软删除的记录。还要注意,在CUSTOMER类中,我为appUsers集合添加了一个@Where
。这是为了仅获取该客户的未被软删除的appUsers。
哇!现在,每当您删除这些实体时,它将把“DELETED”字段设置为“1”,并且当您查询这些实体时,它只会返回包含“DELETED”字段中的‘0’的记录。
难以置信,但使用Hibernate注释实现软删除就是这么简单。
注意:
请注意,您可以使用Hibernate过滤器(
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-filters)来全局过滤所有"已删除"实体,而不是使用
@Where(clause="deleted ‘1’")
语句。我发现定义两个实体管理器(一个用于过滤已删除的项目,另一个用于不过滤已删除的项目,针对罕见情况...)通常非常方便。
使用EntityPersister
您可以创建一个DeleteEventListener,例如:
public class SoftDeleteEventListener extends DefaultDeleteEventListener {
private static final long serialVersionUID = 1L;
@Override
public void onDelete(DeleteEvent event, Set arg1) throws HibernateException {
Object o = event.getObject();
if (o instanceof SoftDeletable) {
((SoftDeletable)o).setStatusId(1);
EntityPersister persister = event.getSession().getEntityPersister( event.getEntityName(), o);
EntityEntry entityEntry = event.getSession().getPersistenceContext().getEntry(o);
cascadeBeforeDelete(event.getSession(), persister, o, entityEntry, arg1);
cascadeAfterDelete(event.getSession(), persister, o, arg1);
} else {
super.onDelete(event, arg1);
}
}
}
将它钩入您的
persistence.xml中,就像这样。
<property name = "hibernate.ejb.event.delete" value = "org.something.SoftDeleteEventListener"/>
另外,不要忘记在注释中更新你的级联。
资源链接:
- Hibernate:使用继承覆盖sql-delete
- 用于CRUD操作的自定义SQL
- 用于创建、更新和删除的自定义SQL