MortalFool
MortalFool

Reputation: 1101

hibernate update to null, then try to delete by updated column

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

Upvotes: 5

Views: 6735

Answers (4)

Nebu
Nebu

Reputation: 131

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

Upvotes: 13

wangf
wangf

Reputation: 925

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

Upvotes: 3

MortalFool
MortalFool

Reputation: 1101

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)

Upvotes: 3

r0bb3n
r0bb3n

Reputation: 71

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

Upvotes: 2

Related Questions