Search code examples
javajpamany-to-onedozer

JPA identifier of an instance of x was altered


Greeting All, I have class called Product and class Supplier. Supplier is parent of Product.

I defined attribute supplier in product with annotation ManyToOne.

After created Product A and Supplier S1, I associate S1 with A first. Then, I created second Supplier S2, when I try to change A's supplier from S1 to S2. The JPA tell me "identifier of an instance of Supplier was altered from X to Y".

I don't require to create/update supplier here. I only want to change supplier from one to another for Product A.

May I know what could went wrong?

   @Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;
    @ManyToOne(cascade=CascadeType.ALL)
    private Company supplier;
...
}

Code from service:

Product productDB=this.findProductByProductIDCurrentUser(productForm.getId());
    dozer.map(productForm, productDB);
    if(productForm.getSupplier()!=null){
        Company company = 
        companyRepository.findOne(productForm.getSupplier().getId() );
        if(company!=null){
            Company supplier = new Company();
            supplier.setId(productForm.getSupplier().getId());
            productDB.setSupplier(supplier);
        }
    }
    em.merge(productDB);

Best Regards, John


Solution

  • You have to make the Supplier 2 managed under the persistence context first.

    Then you can set it as the reference in the Product entity.

    So..

    ProductA productA = session.findProductA(..);
    
    Supplier s2 = new Supplier();
    // construct s2
    
    em.merge(s2);
    
    productA.setSupplier(s2);
    
    em.merge(productA); // optional
    

    Update

    You can also try to detach the product, set product and merge it back again:

    em.detach(product);
    
    product.setSupplier(s2);
    
    em.merge(product);