如下链接作者所述:
我目前正在开发一个需要在数据库中进行软删除的 Seam 应用程序。在右侧,您可以看到我的数据库图表的 sn-p,其中包含 CUSTOMER 和 APP_USER 表。这只是一个简单的一对多关系,但需要注意的重要一点是每个表中的“已删除”字段。这是将用于跟踪软删除的字段。如果该字段包含“1”,则记录已被删除;如果该字段包含“0”,则该记录未被删除。
在像 Hibernate 这样的 ORM 之前,我必须自己使用 SQL 跟踪和设置这个标志。这不会很难做到,但谁愿意编写一堆样板代码来跟踪记录是否已被删除。这就是 Hibernate 和注解发挥作用的地方。
以下是 Hibernate 使用 seamgen 生成的 2 个实体类。为了清楚起见,我省略了部分代码。
客户.java
//Package name...
//Imports...
@Entity
@Table(name = "CUSTOMER")
//Override the default Hibernation delete and set the deleted flag rather than deleting the record from the db.
@SQLDelete(sql="UPDATE customer SET deleted = '1' WHERE id = ?")
//Filter added to retrieve only records that have not been soft deleted.
@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);
// Constructors...
// Getters and Setters...
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "customer")
// Filter added to retrieve only records that have not been soft deleted.
@Where(clause = "deleted <> '1'")
public Set getAppUsers() {
return this.appUsers;
}
public void setAppUsers(Set appUsers) {
this.appUsers = appUsers;
}
}
AppUser.java
//Package name...
//Imports...
@Entity
@Table(name = "APP_USER")
//Override the default Hibernation delete and set the deleted flag rather than deleting the record from the db.
@SQLDelete(sql="UPDATE app_user SET deleted = '1' WHERE id = ?")
//Filter added to retrieve only records that have not been soft deleted.
@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);
// Constructors...
// Getters and Setters...
}
以下两个步骤是我实现软删除所要做的全部。
- 添加了覆盖默认值的
@SQLDelete 注释
该实体的休眠删除。
- 添加
@Where注解过滤查询并只返回
没有被软删除的记录。另请注意,在
CUSTOMER 类我在 appUsers 集合中添加了一个@Where。这是
只需要为该客户获取尚未
被软删除。
维奥拉!现在,无论何时您删除这些实体,它都会将 “DELETED” 字段设置为“1”,当您查询这些实体时,它只会返回 “DELETED”中包含“0”的记录 字段。
难以置信,但这就是使用 Hibernate 注释实现软删除的全部内容。
注意:
还请注意,您可以使用休眠过滤器 (http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-filters) 来全局过滤掉所有“已删除”的实体,而不是使用 @Where(clause="deleted ‘1’") 语句。我发现定义 2 个实体管理器(“正常”一个过滤已删除项目,一个不过滤,在极少数情况下……)通常非常方便。
使用 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: Overwrite sql-delete with inheritace
- Custom SQL for CRUD operations
- Custom SQL for create, update and delete