spring data jpa - Hibernate throws 'ObjectOptimisticLockingFailureException' when saving a @OneToOne with @MapsI

I recently updated my project from Hibernate 5.4 to Hibernate 6.6, and now I’m encountering an error th

I recently updated my project from Hibernate 5.4 to Hibernate 6.6, and now I’m encountering an error that wasn’t happening before.

I have two entities: ProductEntity and ProductProfitabilityEntity, which are part of the same model and share the same ID. These entities are replicated from another microservice, meaning they arrive fully populated, including their IDs. Because of this, there is no @GeneratedValue annotation on their ID fields, as the IDs are assigned externally and must remain unchanged.

  • ProductEntity has a one-to-one relationship with ProductProfitabilityEntity. ProductProfitabilityEntity uses @MapsId, ensuring its ID is always the same as the ProductEntity ID. Both entities reference each other:

    • ProductEntity has a profitability field referencing ProductProfitabilityEntity.
    • ProductProfitabilityEntity has a product field referencing ProductEntity.

ProductEntity:

package br.triersistemas.cloud.platform.desktop.entity.product;

import br.triersistemas.cloud.database.entity.AuditingExternalEntity;
import br.triersistemas.cloud.platform.desktop.entity.productprofitability.ProductProfitabilityEntity;
import jakarta.persistence.*;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

import java.util.UUID;

@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
@Entity
@Table(name = "product")
public class ProductEntity extends AuditingExternalEntity {

    @Getter
    @Setter
    @Id
    @Column(name = "id")
    private UUID id;

    @Getter
    @Setter
    @Column(name = "product_code")
    private Long productCode;

    // Contains one ProductProfitabilityEntity
    @Valid
    @OneToOne(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private ProductProfitabilityEntity profitability;
}

ProductProfitabilityEntity:

package br.triersistemas.cloud.platform.desktop.entity.productprofitability;

import br.triersistemas.cloud.database.entity.AuditingEntity;
import br.triersistemas.cloud.platform.desktop.entity.product.ProductEntity;
import jakarta.persistence.*;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

import java.util.UUID;

@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
@Entity
@Table(name = "product_profitability")
public class ProductProfitabilityEntity extends AuditingEntity {

    @NotNull(message = "Unique identifier is required.")
    @Getter
    @Setter
    @Id
    @Column(name = "id")
    private UUID id;

    // Refers to the container ProductEntity
    // Using OneToOne with MapsId, so: ProductProfitabilityEntity.id = ProductEntity.id
    @Valid
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "id")
    @MapsId
    private ProductEntity product;
}

The Issue

When I try to save ProductEntity, I get the following error:

.springframework.orm.ObjectOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [br.triersistemas.cloud.platform.desktop.entity.productprofitabilityentity.ProductProfitabilityEntity#fb01b3e0-f12e-4380-b82a-2f2882fadaf1]

My Understanding of the Problem:

Hibernate sees that ProductProfitabilityEntity already has an ID and tries to fetch it from the database to determine whether it should perform an update or an insert. However, since the entity does not exist yet, it likely throws this exception.

I didn't expect that, because there is no @GeneratedValue and the entity does not exist, Hibernate would insert it with the provided ID instead of failing.

If I manually set the id of ProductProfitabilityEntity to null before saving, everything works fine—Hibernate properly inserts it and maps the relationship. However, since my API receives fully populated replicated data (which used to work before), setting the ID to null is not an ideal solution.

What Changed in Hibernate 6.6?

Before the update, this issue didn’t occur. I am trying to understand

  1. What has changed in Hibernate 6.6 that is now causing this behavior?
  2. Is there a better solution than manually setting ProductProfitabilityEntity.id = null before saving ProductEntity?

I recently updated my project from Hibernate 5.4 to Hibernate 6.6, and now I’m encountering an error that wasn’t happening before.

I have two entities: ProductEntity and ProductProfitabilityEntity, which are part of the same model and share the same ID. These entities are replicated from another microservice, meaning they arrive fully populated, including their IDs. Because of this, there is no @GeneratedValue annotation on their ID fields, as the IDs are assigned externally and must remain unchanged.

  • ProductEntity has a one-to-one relationship with ProductProfitabilityEntity. ProductProfitabilityEntity uses @MapsId, ensuring its ID is always the same as the ProductEntity ID. Both entities reference each other:

    • ProductEntity has a profitability field referencing ProductProfitabilityEntity.
    • ProductProfitabilityEntity has a product field referencing ProductEntity.

ProductEntity:

package br.triersistemas.cloud.platform.desktop.entity.product;

import br.triersistemas.cloud.database.entity.AuditingExternalEntity;
import br.triersistemas.cloud.platform.desktop.entity.productprofitability.ProductProfitabilityEntity;
import jakarta.persistence.*;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

import java.util.UUID;

@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
@Entity
@Table(name = "product")
public class ProductEntity extends AuditingExternalEntity {

    @Getter
    @Setter
    @Id
    @Column(name = "id")
    private UUID id;

    @Getter
    @Setter
    @Column(name = "product_code")
    private Long productCode;

    // Contains one ProductProfitabilityEntity
    @Valid
    @OneToOne(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private ProductProfitabilityEntity profitability;
}

ProductProfitabilityEntity:

package br.triersistemas.cloud.platform.desktop.entity.productprofitability;

import br.triersistemas.cloud.database.entity.AuditingEntity;
import br.triersistemas.cloud.platform.desktop.entity.product.ProductEntity;
import jakarta.persistence.*;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

import java.util.UUID;

@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
@Entity
@Table(name = "product_profitability")
public class ProductProfitabilityEntity extends AuditingEntity {

    @NotNull(message = "Unique identifier is required.")
    @Getter
    @Setter
    @Id
    @Column(name = "id")
    private UUID id;

    // Refers to the container ProductEntity
    // Using OneToOne with MapsId, so: ProductProfitabilityEntity.id = ProductEntity.id
    @Valid
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "id")
    @MapsId
    private ProductEntity product;
}

The Issue

When I try to save ProductEntity, I get the following error:

.springframework.orm.ObjectOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [br.triersistemas.cloud.platform.desktop.entity.productprofitabilityentity.ProductProfitabilityEntity#fb01b3e0-f12e-4380-b82a-2f2882fadaf1]

My Understanding of the Problem:

Hibernate sees that ProductProfitabilityEntity already has an ID and tries to fetch it from the database to determine whether it should perform an update or an insert. However, since the entity does not exist yet, it likely throws this exception.

I didn't expect that, because there is no @GeneratedValue and the entity does not exist, Hibernate would insert it with the provided ID instead of failing.

If I manually set the id of ProductProfitabilityEntity to null before saving, everything works fine—Hibernate properly inserts it and maps the relationship. However, since my API receives fully populated replicated data (which used to work before), setting the ID to null is not an ideal solution.

What Changed in Hibernate 6.6?

Before the update, this issue didn’t occur. I am trying to understand

  1. What has changed in Hibernate 6.6 that is now causing this behavior?
  2. Is there a better solution than manually setting ProductProfitabilityEntity.id = null before saving ProductEntity?
Share Improve this question edited Mar 11 at 14:17 Nikolas Trapp asked Mar 11 at 14:09 Nikolas TrappNikolas Trapp 899 bronze badges 1
  • Fot to mention that, if i persist the ProductProfitabilityEntity before saving the Product, everything works fine too. – Nikolas Trapp Commented Mar 11 at 14:10
Add a comment  | 

1 Answer 1

Reset to default 0

Solved by removing @MapsId from ProductProfitabilityEntity.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744789562a4593831.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信