休眠@SQLDelete sql 不添加架构

2022-09-02 14:11:37

我正在尝试使用Hibernate的注释进行软删除。当数据库模式是静态的时,它工作得很好,即:在SQL中传递它。
不幸的是,似乎SQL是按原样传递给s(cf的方法,所以我找不到一种方法来动态传递架构名称,就像在本机SQL查询中使用一样
,有没有人找到解决这个问题的好办法(我使用的是Hibernate 4.3.5)?@SQLDeleteEntityPersisterEntityClassCustomSQL createCustomSQL(AnnotationInstance customSqlAnnotation){h-schema}

编辑:除非有真正的解决方案,否则我最终通过在方法中设置自定义SQL查询时替换架构占位符来修改代码源。org.hibernate.persister.entity.AbstractEntityPersisterdoLateInit

编辑2:我在Hibernate JIRA中为这种行为创建了一个问题。我将在今天晚些时候创建一个拉取请求,我希望Hibernate团队能够接受它


答案 1

使用休眠注释进行软删除。

正如链接的作者在下面所说:

我目前正在开发一个需要在数据库中进行软删除的Seam应用程序。在右侧,您可以看到我的数据库关系图的一个片段,其中包含一个和表。这只是一个直截了当的关系,但重要的是要注意每个表中的“已删除”字段。这是将用于跟踪软删除的字段。如果字段包含“1”,则记录已被删除,如果包含“0”,则记录尚未删除。CUSTOMERAPP_USER

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
  2. 添加了注释以筛选查询并仅返回尚未软删除的记录。另请注意,在 CUSTOMER 类中,我向 appUsers 集合添加了 。这是仅获取该客户的尚未软删除的应用程序用户所必需的。@Where@Where

中提琴!现在,每当您删除这些实体时,它都会将“已删除”字段设置为“1”,当您查询这些实体时,它将仅返回在“已删除”字段中包含“0”的记录。

难以置信,但这就是使用Hibernate注释实现软删除的全部内容。

注意:

另请注意,您可以使用休眠过滤器(http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-filters)全局过滤掉所有“已删除”实体,而不是使用语句。我发现定义2个实体管理器(“正常”一个过滤已删除的项目,一个不过滤已删除的项目,对于极少数情况......)通常非常方便。@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);
    }
}
}

把它钩到你的坚持中.xml就像这样

<property name = "hibernate.ejb.event.delete" value = "org.something.SoftDeleteEventListener"/> 

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

资源链接:

  1. 休眠:使用继承覆盖 sql 删除
  2. 用于 CRUD 操作的自定义 SQL
  3. 用于创建、更新和删除的自定义 SQL

答案 2

像这样使用

@SQLDelete(sql = "UPDATE {h-schema}LEAVE  SET STATUS = 'DELETED' WHERE id = ?", check = ResultCheckStyle.COUNT)

推荐