5

I want just that those attributes which are not used will get removed from DB (orphanRemoval=true). What I got is that it first tries to update the refrence PRODUCT_ID and then delete its. but as the refrence is part of the key it cannot.

Parent:

    @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;
    ...

Its Child

    @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;
        ...

After i take a list of attributes and clear then, and thtne try to commit i get

    ...
    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
    ...

Does anyone know why Hibernate tries to update the reference first, and then deletes it. Can I somehow prevent it from. All I want is that those childs(attributes) which are not used have to get deleted and not just cut the reference. ...

MortalFool
  • 1,065
  • 2
  • 14
  • 26

4 Answers4

12

I had similar issues. Using "updatable = false" has worked for me.

You can try out below code :

@OneToMany(fetch = FetchType.LAZY,  cascade=CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "PRODUCT_ID", referencedColumnName = "PRODUCT_ID", updatable = false)
private Set<Attribute> attributes
Jeel Vankhede
  • 11,592
  • 2
  • 28
  • 58
Nebu
  • 121
  • 1
  • 2
3

Seems like my issue is similar to this one:

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)

Community
  • 1
  • 1
MortalFool
  • 1,065
  • 2
  • 14
  • 26
3

I search on google for this issue but did not get a answer. Hibernate issue a update SQL before delete, the update SQL try set a non-nullable column to null, then exception happen. I do not know why Hibernate issue update before delete.

At last I use custom delete JPQL instead of Spring Data JPA standard delete method.

@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);
}
wangf
  • 895
  • 9
  • 12
2

I think there is a problem about the relationship. You have to map entities, not specific columns of them.

I suggest the following construct:

@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;
...

And the attribute:

@Entity
@Table(name="ATTRIBUTE")
public class Attribute{

    ...

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PRODUCT_ID", nullable = false)
    protected Style style;
    ...

There is no explicit ID for the referenced parent entity Style. Hibernate resolve it to its entity.

Why do you use such a complicated ID in your attribute class?

B.T.W.: By default there is no deterministic order for child entities, so you should better use a Set instead of List

r0bb3n
  • 61
  • 3
  • I dont need a back reference. Thats why i use joincolums and not mappedBy. Also i dont use mappedBy beacuse there are other entities which should be able to use attributes also. – MortalFool Jun 04 '14 at 10:12