【问题标题】:Deleting an entity with a List<String> causes "Referential integrity constraint violation"删除具有 List<String> 的实体会导致“违反参照完整性约束”
【发布时间】:2021-10-19 04:53:45
【问题描述】:

我有一个带有字符串列表的实体(“Saunoja”)。尝试从 H2-console 中删除 Saunoja 时,出现以下错误:

Referential integrity constraint violation: "FKIL684UE3YHG0N80RMHVIFQTA0: PUBLIC.SAUNOJA_ROLES FOREIGN KEY(SAUNOJA_ID) REFERENCES PUBLIC.SAUNOJA(ID) (1)"; SQL statement: DELETE FROM "PUBLIC"."SAUNOJA" WHERE "ID"=? [23503-200]

我在 Saunoja 实体的另一个属性上遇到了同样的问题,但它已通过对之前在此处提出的类似问题的回答得到解决。 因为这个属性是一个由antohter Entity组成的List,并且@OneToMany关系存在问题,所以解决方案是添加一个@OnDelete(action = OnDeleteAction.CASCADE),但在这种情况下它不起作用,因为它不是实际的@OneToMany 关系。

atm 我的实体看起来像这样:

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Saunoja extends AbstractPersistable<Long> implements Comparable<Saunoja> {

    private String username;

    private String password;

    private String firstName;

    private String lastName;

    @Cascade(org.hibernate.annotations.CascadeType.ALL)
    @ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
    private List<String> roles;

    private LocalDateTime created;

    private Long profilepictureId;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private List<Photo> photos;

    @Override
    public int compareTo(Saunoja other) {

        return username.compareToIgnoreCase(other.username);
    }

}

为持久化角色制作了一个单独的表。该表称为 SAUNOJA_ROLES。可能与字符串列表的注释有关..?

已经尝试过这样(以及各种组合):

    @ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JoinColumn
    private List<String> roles;

【问题讨论】:

    标签: spring-boot hibernate h2


    【解决方案1】:

    似乎将对象属性注释为 ElementCollection 会导致很难或不可能像往常一样直接删除相关实体:https://hibernate.atlassian.net/browse/HHH-5528

    ElementCollection 是使用字符串列表的方式。

    因此,我对该问题的解决方案是在删除实体之前以编程方式擦除列表。似乎没有办法将删除级联到列表中。无论如何,这暂时解决了我的问题:

    @PreAuthorize("hasAuthority('GOD')")
        public void deleteSaunoja(String username) {
    
            Saunoja saunoja = saunojaRepository.findByUsername(username);
    
            if (saunoja != null) {
                            
                saunoja.getRoles().clear();
    
                saunojaRepository.save(saunoja);
    
                saunojaRepository.delete(saunoja);
                
                deletedSaunojaRepository.save(new DeletedSaunoja(username, LocalDateTime.now()));
            }
        }
    

    【讨论】:

    • 如您所见,这是一个未解决的问题。它最终会被修复,但如果这对您现在很重要,您可以尝试自己提供修复或聘请某人为您执行此操作,例如红帽或顾问。 FWIW,您可以为此目的使用 Blaze-Persistence Entity-Views,它提供了一种方法 entityViewManager#remove(Object),该方法以更有效的方式处理删除并正确考虑已加载的数据:github.com/Blazebit/blaze-persistence#entity-view-usage
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    相关资源
    最近更新 更多