java - Hibernate @SQLDelete sql 不添加模式

标签 java sql hibernate schema abstract

我正在尝试使用 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”,则记录未被删除。

enter image description here

在像 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 个步骤是我实现软删除所要做的全部。

  1. 添加了覆盖默认值的 @SQLDelete 注解 hibernate 删除该实体。
  2. 添加了@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"/> 

此外,不要忘记在注释中更新级联。

资源链接:

  1. Hibernate: Overwrite sql-delete with inheritace
  2. Custom SQL for CRUD operations
  3. Custom SQL for create, update and delete

关于java - Hibernate @SQLDelete sql 不添加模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38791394/

相关文章:

基于MySQL查询输出的PHP决策

php - PHP/MYSQL编辑配置文件功能-错误的查询语法?

java - spring中的hibernate不保存mysql数据库

java - 相当于Hibernate中的ResultSet.getRow()

java - 如何检查 hibernate 更新是否完成?

java - 输入内容后,交互 Pane 停止并继续显示加载图标

java - 测试代码来比较 jackson Stream 与 Map - 这工作正常吗?

java - 结果集到多 HashMap

java - Netty 客户端相对于 I/O 客户端的优势?

SQL 批量字符串操作