2017-11-11 224 views
0

仅供参考https://hibernate.atlassian.net/browse/HHH-12104@Where注解与@ManyToOne关系检索软删除实体

我有CustomerProject实体之间的双向OneToMany关系。两者都支持SOFT删除。当我加载Project时,即使它被SOFT删除,我也可以检索Customer。只有当ManyToOne被EAGERly提取时才会发生。

我写的显示问题测试用例:

Create a Customer and a Project 
SOFT Delete only the Customer 
Fetch the Project 

我除了Project有没有Customer,因为它已被删除。

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

测试用例(FAIL):

@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) { 
     } 

    } 

Customer实体(AbstractEntity具有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); 
    } 
} 

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); 
    } 
} 

回答

0

它MIG这是一个bug,所以随时添加一个复制测试用例的Jira问题。

对于周围的工作,看看this article

@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 { 

    ... 
} 

因此,使用专用的@Loaded其中包括deleted列好。

+0

使用'Loader'不能解决问题。我会打开一个Jira问题 – Sydney