我正在尝试使用Hibernate的@SQLDelete
注释进行软删除。当DB模式是静态的时,它很有效,即:在SQL中传递它
不幸的是,似乎SQL按原样传递给EntityPersister
s(cf EntityClass
的方法CustomSQL createCustomSQL(AnnotationInstance customSqlAnnotation)
,所以我找不到像Native SQL一样动态传递模式名称的方法使用{h-schema}
的查询
有没有人为这个问题找到一个好的解决方法(我使用的是Hibernate 4.3.5)?
编辑:除非有真正的解决方案,否则我在方法org.hibernate.persister.entity.AbstractEntityPersister
中设置自定义SQL查询时,通过替换架构占位符来修改doLateInit
的代码源。
Edit2 :我在Hibernate JIRA中为此行为创建了an issue。我今天晚些时候会创建一个拉取请求,我希望Hibernate团队接受它
答案 0 :(得分:0)
像这样使用
@SQLDelete(sql = "UPDATE {h-schema}LEAVE SET STATUS = 'DELETED' WHERE id = ?", check = ResultCheckStyle.COUNT)
答案 1 :(得分:0)
答案 2 :(得分:-1)
如链接作者所述:
我目前正在开发一个需要在数据库中进行软删除的Seam应用程序。在右侧,您可以看到我的数据库图表的片段,其中包含CUSTOMER
和APP_USER
表。这只是一个直接的一对多关系,但重要的是要注意每个表中的“DELETED”字段。这是将用于跟踪软删除的字段。如果该字段包含“1”,则该记录已被删除,如果该字段包含“0”,则该记录尚未删除。
在像Hibernate之类的ORM之前,我必须使用SQL自己跟踪和设置这个标志。这样做并不是很难,但是谁想要编写一堆样板代码只是为了跟踪记录是否已被删除。这就是Hibernate和注释的用武之地。
下面是Hibernate使用seamgen生成的2个Entity类。为清楚起见,我省略了部分代码。
//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;
}
}
//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
注释
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’")
语句。我发现定义了两个实体管理器(“正常”一个过滤掉已删除的项目,另一个没有,对于极少数情况......)通常非常方便。
您可以创建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"/>
另外,请勿忘记在注释中更新您的级联。