【问题标题】:hibernate update to null, then try to delete by updated column休眠更新为null,然后尝试按更新列删除
【发布时间】:2014-06-03 15:44:24
【问题描述】:

我只想将那些未使用的属性从数据库中删除(orphanRemoval=true)。 我得到的是它首先尝试更新参考 PRODUCT_ID 然后删除它。但由于引用是密钥的一部分,它不能。

家长:

    @Entity
    @Table(name = "STYLE")
    public class Style implements IterableById, Serializable {
    ...
        @OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, orphanRemoval=true)
        @JoinColumn(name="PRODUCT_ID", referencedColumnName = "PRODUCT_ID")
        private List<Attribute> attributes;
    ...

它的孩子

    @Entity
    @Table(name="ATTRIBUTE")
    public class Attribute{
        @EmbeddedId
        private Id id;
        ...

        @Embeddable
        public static class Id implements Serializable{

        private static final long serialVersionUID = -8631874888098769584L;

        @Column(name="PRODUCT_ID")
        protected Long productId;

        @Column(name="NAME")
        protected String name;

        @Column(name="COUNTRY_CODE")
        protected String countryCode;
        ...

在我获取属性列表并清除之后,然后尝试提交我得到

    ...
    Hibernate: update ATTRIBUTE set PRODUCT_ID=null where PRODUCT_ID=?
    Hibernate: delete from ATTRIBUTE where COUNTRY_CODE=? and NAME=? and PRODUCT_ID=?
    javax.persistence.RollbackException: Error while committing the transaction
    Caused by: javax.persistence.OptimisticLockException: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    ...

有谁知道为什么 Hibernate 会先尝试更新引用,然后再删除它。我能以某种方式阻止它。我想要的是那些不使用的孩子(属性)必须被删除,而不仅仅是削减参考。 ...

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    我也有类似的问题。使用“updatable = false”对我有用。

    你可以试试下面的代码:

    @OneToMany(fetch = FetchType.LAZY,  cascade=CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "PRODUCT_ID", referencedColumnName = "PRODUCT_ID", updatable = false)
    private Set<Attribute> attributes
    

    【讨论】:

    • 我已经为这个错误苦苦挣扎了很久。终于成功了。
    【解决方案2】:

    好像我的问题和这个类似:

    How can I map "insert='false' update='false'" on a composite-id key-property which is also used in a one-to-many FK?

    @JoinColumn(name="PRODUCT_ID", referencedColumnName = "PRODUCT_ID", insertable = false, updatable = false)

    【讨论】:

      【解决方案3】:

      我在谷歌上搜索这个问题,但没有得到答案。 Hibernate 在删除前发出更新 SQL,更新 SQL 尝试将不可为空的列设置为 null,然后发生异常。我不知道为什么 Hibernate 在删除前更新问题。

      最后我使用自定义删除 JPQL 而不是 Spring Data JPA 标准删除方法。

      @Repository
      public interface ProductRepository extends PagingAndSortingRepository<Product, Long> {
      
      	Product findByName(String name);
      
      	String jpql_deleteById = "delete from Product p where p.id = :id";
      
      	@Modifying
      	@Query(jpql_deleteById)
      	void deleteById(@Param("id") Long id);
      }

      【讨论】:

        【解决方案4】:

        我认为关系有问题。您必须映射实体,而不是它们的特定列。

        我建议以下构造:

        @Entity
        @Table(name = "STYLE")
        public class Style implements IterableById, Serializable {
        ...
            @OneToMany(fetch = FetchType.LAZY, mappedBy = "style", cascade=CascadeType.ALL, orphanRemoval = true)
            private Set<Attribute> attributes;
        ...
        

        以及属性:

        @Entity
        @Table(name="ATTRIBUTE")
        public class Attribute{
        
            ...
        
            @ManyToOne(fetch = FetchType.LAZY)
            @JoinColumn(name = "PRODUCT_ID", nullable = false)
            protected Style style;
            ...
        

        引用的父实体 Style 没有明确的 ID。 Hibernate 将其解析为它的实体。

        为什么要在属性类中使用这么复杂的 ID?

        B.T.W.:默认情况下,子实体没有确定的顺序,因此您最好使用 Set 而不是 List

        【讨论】:

        • 我不需要反向引用。这就是我使用joincolums而不是mappedBy的原因。我也不使用 mappedBy,因为还有其他实体也应该能够使用属性。
        猜你喜欢
        • 2013-07-28
        • 1970-01-01
        • 2019-07-12
        • 1970-01-01
        • 1970-01-01
        • 2010-11-21
        • 2011-11-06
        • 2011-09-28
        • 2023-04-10
        相关资源
        最近更新 更多