我正在尝试使用 Hibernate 的 @SQLDelete
注解来进行软删除。当数据库模式是静态的,即:在 SQL 中传递它时,它工作得很好。
不幸的是,SQL 似乎按原样传递给了 EntityPersister
(参见 EntityClass
的方法 CustomSQL createCustomSQL(AnnotationInstance customSqlAnnotation)
,所以我不能'找不到像使用 {h-schema}
的 native SQL 查询那样动态传递架构名称的方法
有没有人找到解决此问题的好方法(我使用的是 Hibernate 4.3.5)?
编辑:除非有真正的解决方案,否则我最终修改了 org.hibernate.persister.entity.AbstractEntityPersister
的代码源,方法是在方法 doLateInit
。
Edit2:我创建了an issue对于 Hibernate JIRA 中的这种行为。我将在今天晚些时候创建一个拉取请求,我希望 Hibernate 团队能够接受它
最佳答案
Soft deletes using Hibernate annotations.
如下链接作者所述:
我目前正在开发一个需要在数据库中进行软删除的 Seam 应用程序。在右侧,您可以看到我的数据库图表的片段,其中包含一个 CUSTOMER
和一个 APP_USER
表。这只是一个直接的一对多关系,但需要注意的重要一点是每个表中的“DELETED”字段。这是将用于跟踪软删除的字段。如果该字段包含“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;
}
}
应用用户.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...
}
以下 2 个步骤是我实现软删除所要做的全部。
- 添加了覆盖默认值的
@SQLDelete
注解 hibernate 删除该实体。 - 添加了
@Where
注解来过滤查询,只返回 没有被软删除的记录。另请注意,在 CUSTOMER 类 我向 appUsers 集合添加了一个@Where
。这是 只需要为该客户获取尚未获取的 appUsers 被软删除。
中提琴!现在,无论何时您删除这些实体,它都会将 “DELETED” 字段设置为“1”,当您查询这些实体时,它只会返回在 “DELETED”中包含“0”的记录 字段。
难以置信,但这就是使用 Hibernate 注释实现软删除的全部内容。
注意事项:
另请注意,除了使用 @Where(clause="deleted '1'")
语句之外,您还可以使用 hibernate 过滤器 ( http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-filters ) 全局过滤掉所有“已删除”的实体.我发现定义 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"/>
此外,不要忘记在注释中更新级联。
资源链接:
关于java - Hibernate @SQLDelete sql 不添加模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38791394/