9

My Entities:

@Entity
public class Document  {

   @Id
   protected String id; //It string in purpose

   @OneToOne(cascade = ALL)
   @JoinColumn(name = "DOCUMENT_DETAILS")
   private DocumentDetails details;

} 

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "documentDiscr")
@EqualsAndHashCode
public abstract class DocumentDetails {

   @Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
   private Long id;

   private Money total;

   @ManyToOne(cascade = CascadeType.ALL)
   @JoinColumn(name = "SELLER_ID")
   private Company seller;

   @ManyToOne(cascade = CascadeType.ALL)
   @JoinColumn(name = "BUYER_ID")
   private Company buyer;
}

@Entity
public class Company {

   @Id
   protected String id;

   private String name;
   private String phoneNumber;
   private String email;

   @OneToOne(cascade = CascadeType.ALL)
   @JoinColumn(name = "address_id")
   private Address address;
}

@Entity
@EqualsAndHashCode
public class Address {

   @Id
   @GeneratedValue(strategy= GenerationType.SEQUENCE)
   private Long id;
   private String country;
   private String city;
   private String postalCode;
   private String streetName;
   private String streetNumber;
   private String apartmentNumber;
}

@Path("path")
@Transactional 
public class MyResource {

   @Inject
   MyRepo myRepo;

   @PUT
   public Document updateDoc(Document document){
       myRepo.update(document);
   }

}

public class Repo<T extends MyClass> implements MyRepo<T> {

    @PersistenceContext
    protected EntityManager entityManager;


    public T create(T t) {
       t.generateId();
       this.entityManager.persist(t);
       return t;
    }

    public T update(T entity) {
       return entityManager.merge(entity);
    }

}

When I call entityManage.update(documentEntity) and same Company is added as supplier and buyer I see 'Multiple representations of the same entity'.

I read this but nothing helps. When I removed CascadeType.All I am getting

'detached entity passed to persist: my.pckg.Address'

I also tried to remove CascadeType.Merge but error is the same. What I can do? Where is my mistake?

UPDATE

First I changed @ManyToOne(Cascade.All) to @ManyToOne() in DocumentDetails

Second I changed @ManyToOne(Cascade.All) to @ManyToOne(Cascade.Merge) in DocumentDetails.

Third I I changed @ManyToOne(Cascade.All) to @ManyToOne(all types except all and merge) in DocumentDetails.

I also tried same with Address class

Community
  • 1
  • 1
Krzysztof
  • 1,861
  • 4
  • 22
  • 33
  • can you add the transactional method which is persisting the entity? – Maciej Kowalski Jan 27 '17 at 17:32
  • also from which mapprings did you remove the cascade? – Maciej Kowalski Jan 27 '17 at 17:44
  • When you say the same Company is added as supplier and buyer, do you mean just that the values are the same, or that it's actually the same object? – Douglas Jan 27 '17 at 19:15
  • @MaciejKowalski I updated the post :) – Krzysztof Jan 27 '17 at 19:23
  • @Douglas Probably same values but not objects. I am not sure how Jeresy deserialise Json. In debug I saw that these objects has different references like Company@123 and Company@125 – Krzysztof Jan 27 '17 at 19:26
  • whats your hibernate / spring version? – Maciej Kowalski Jan 27 '17 at 21:24
  • @MaciejKowalski I am using spring boot, but even when I explicty declared in pom `Hibernate 5.2.6.FINAL` nothing chnages – Krzysztof Jan 27 '17 at 21:38
  • 2
    "Probably same values but not objects. " - this is the root cause. I would not expect that hibernate will just save whatever was deserialized from JSON. Some manual work will be needed here to get actual data from DB and have managed entities. For example you won't be able to persist a new document mapped to existing company. Cascading persist will fail on company entity. Try using Spring Data REST to do it for you. – Piotr Gwiazda Jan 27 '17 at 22:40
  • @PiotrGwiazda Thank you for your explanation! I will look at Spring Data REST but I will also try to do manual work. If you can advice me something to start with manual fix I will be very gratefull. – Krzysztof Jan 27 '17 at 23:00
  • Try to remove `@EqualsAndHashCode` annotation from the entities. – Dherik Jan 28 '17 at 15:55
  • @Dherik I added this when problem occurs but this not solve it. I leave it becouse I thought that it is a good idea to have it – Krzysztof Jan 28 '17 at 21:28
  • This happens when you overwrite the object with same value but with different hashcode – ABHAY JOHRI Dec 18 '17 at 14:18
  • Possible duplicate of [java.lang.IllegalStateException: Multiple representations of the same entity with @ManyToMany 3 entities](https://stackoverflow.com/questions/26591521/java-lang-illegalstateexception-multiple-representations-of-the-same-entity-wit) – Jens Schauder Aug 27 '18 at 05:04

2 Answers2

4

Ok - with hint from Piotr Gwiazda I solved it.

Simple and naive solution is add:

if(seller != null && buyer != null){
   if(seller.equals(buyer)){
       document.getDetails.setSeller(document.getDetails().getBuyer());
   }
}

(better answer is SpringData)

before update(). This situation has place because when two different objects are equal but they references that are different hibernate can't handle them as same object.

Krzysztof
  • 1,861
  • 4
  • 22
  • 33
2

This happens when you overwrite the object with same value but with different hashcode, If i am having employee class and employee is having the address class and if I will save the same employee with same address value but with different hashcode then I will get this issue, If I will clone address and set in employee then Hibernate will get confused and not able to save data

@Entity
@Getter
@Setter
class Person implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id", unique = true, nullable = false)
    private Long id;

    @OneToMany(cascade= CascadeType.ALL)
    private Set<Address> Addresses = new HashSet<>();

    protected Person(){}
}

@Entity
@Getter
@Setter
class Address implements Serializable {
    @EmbeddedId
    private AddressId addressId;
    private State state;
    protected Address(){}
}

@Embeddable
@Getter
@Setter
public class AddressId implements Serializable {
    @Column(name = "person_id")
    private Long personId;
    @Column(name = "postcode")
    private String postcode;
}

Solution For this

AddressId addressId = new AddressId();
addressId.setPersonId(personId);
addressId.setPostcode("4000"); //person already has an address with this postcode
Address address = null;
for (Address a : person.getAddresses()) {
    if (a.getAddressId().equals(addressId)) {
        address = a;
        break;
    }
}
if (address == null) {
    address = new Address();
    address.setAddressId(addressId);
    address.setState(State.ABC); //but I want to change the state from QLD to TAS
    person.getAddresses().add(address);
}
else {
    address.setState(State.TAS);
}
person = personRepo.save(person);
ABHAY JOHRI
  • 1,997
  • 15
  • 19