具有@ManyToOne关系的@Where注释检索软删除的实体

Syd*_*ney 5 java hibernate jpa

供参考https ://hibernate.atlassian.net/browse/HHH-12104

我在和实体之间有双向OneToMany关系。两者都支持软删除。当我加载 a 时,即使它被软删除,我也可以检索它。仅当急切获取时才会发生这种情况。CustomerProjectProjectCustomerManyToOne

我写了一个测试用例来显示这个问题:

Create a Customer and a Project
SOFT Delete only the Customer
Fetch the Project
Run Code Online (Sandbox Code Playgroud)

自从它被删除后我就Project没有了。Customer

您可能会认为测试用例是错误的,因为完整性被破坏了。这在逻辑上是正确的,但在物理上却不然(FOREIGN KEY 约束仍然有效)。我在一个真实的项目中看到过这样的案例。好的实现是删除所有项目,然后删除客户。

测试用例(失败):

@RunWith(SpringRunner.class)
@DataJpaTest
public class SoftDeleteTest {

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private ProjectRepository projectRepository;

    @Autowired
    private CustomerRepository customerRepository;

    private void newSession() {
        entityManager.flush();
        entityManager.clear();
    }

    @Test
    public void testIntegrityConstraintManyToOne() {
        Project project = new Project();
        project.setName("Framework");

        Customer customer = new Customer();
        customer.setName("StackOverflow");
        customer.addProject(project);

        customerRepository.save(customer);
        projectRepository.save(project);

        Long customerId = customer.getId();
        Long projectId = project.getId();

        newSession();
        customerRepository.delete(customerId);

        newSession();
        Project orphanProject = projectRepository.findOne(projectId);
        try {
            Customer deletedCustomer = orphanProject.getCustomer();
            deletedCustomer.toString();
            fail("EntityNotFoundException expected");
        } catch (EntityNotFoundException enfe) {
        }

    }
Run Code Online (Sandbox Code Playgroud)

实体CustomerAbstractEntity有一个Boolean deleted字段):

@Entity
@Table(name = "CUSTOMER")
@SQLDelete(sql = "UPDATE customer SET deleted = TRUE WHERE id = ?")
@Where(clause = "deleted = false")
public class Customer extends AbstractEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "customer")
    private Set<Project> projects = new HashSet<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Project> getProjects() {
        return projects;
    }

    public void setProjects(Set<Project> projects) {
        this.projects = projects;
    }

    public void addProject(Project project) {
        projects.add(project);
        project.setCustomer(this);
    }

    public void removeProject(Project project) {
        projects.remove(project);
        project.setCustomer(null);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Customer customer = (Customer) o;
        return Objects.equals(id, customer.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
Run Code Online (Sandbox Code Playgroud)

实体Project

@Entity
@Table(name = "PROJECT")
@SQLDelete(sql = "UPDATE project SET deleted = true WHERE id = ?")
@Where(clause = "deleted = false")
public class Project extends AbstractEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.EAGER)
    private Customer customer;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Project)) return false;
        Project project = (Project) o;
        return Objects.equals(id, project.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
Run Code Online (Sandbox Code Playgroud)

Vla*_*cea 0

这可能是一个错误,因此请随意添加带有复制测试用例的 Jira 问题。

要解决此问题,请查看这篇文章

@Entity(name = "PostDetails")
@Table(name = "post_details")
@SQLDelete(sql = 
    "UPDATE post_details " +
    "SET deleted = true " +
    "WHERE id = ?")
@Loader(namedQuery = "findPostDetailsById")
@NamedQuery(name = "findPostDetailsById", query = 
    "SELECT pd " +
    "FROM PostDetails pd " +
    "WHERE " +
    "   pd.id = ?1 AND " +
    "   pd.deleted = false")
@Where(clause = "deleted = false")
public class PostDetails 
    extends BaseEntity {

    ...
}
Run Code Online (Sandbox Code Playgroud)

因此,请使用也@Loaded包括该列的专用工具。deleted