72

I have 3 entities with ManyToMany relationships:

Role Entity:

@Entity
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer roleID;
    private String roleName;
    private String description;

    @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.EAGER)
    @JoinTable(name = "role_permission", joinColumns = {@JoinColumn(name = "role_id")}, inverseJoinColumns = {@JoinColumn(name = "permission_id")})
    private Set<Permission> permissions = new LinkedHashSet<Permission>();
}

Permission Entity:

@Entity
public class Permission {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int permissionID;
    private String permissionName;
    private String description;

    @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.EAGER)
    @JoinTable(name = "permission_functionality", joinColumns = {@JoinColumn(name = "permission_id")}, inverseJoinColumns = {@JoinColumn(name = "functionality_id")})
    private Set<Functionality> functionalities = new LinkedHashSet<>();
}

Functionality Entity:

@Entity
public class Functionality {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
}

I did the following:

  1. I have created 3 functionalities:

    Functionality1, Functionality2, Functionality3
    
  2. Then created 2 permissions:

    Permission1 with Functionality1, Functionality2
    
    Permission2 with Functionality2, Functionality3
    
  3. Then created a role:

    Role1 with Permission1 and Permission2 
    

I am getting the following exception:

java.lang.IllegalStateException: Multiple representations of the same entity [com.persistence.entity.admin.Functionality#1] are being merged. Detached: [com.persistence.entity.admin.Functionality@4729256a]; Detached: [com.persistence.entity.admin.Functionality@56ed25db]

Sam
  • 2,856
  • 3
  • 18
  • 29
user1188867
  • 3,726
  • 5
  • 43
  • 69

15 Answers15

62

Fixed it by removing CascadeType.MERGE on Permission entity

user1188867
  • 3,726
  • 5
  • 43
  • 69
  • 8
    Try using Hibernate cascade annotations instead of JPA annotations. Eg.,@Cascade(CascadeType.SAVE_UPDATE) would replace {CascadeType.PERSIST,CascadeType.MERGE }. Check this article: [JPA & Hibernate annotation common mistake](https://www.mkyong.com/hibernate/cascade-jpa-hibernate-annotation-common-mistake/) – Mate Šimović May 21 '17 at 20:26
  • 5
    What effect does this have if I want to merge existing entities? What happens when I remove `CascadeType.MERGE`? – El Mac May 16 '18 at 11:01
  • Yes, having the same question, what happens when we remove the MERGE cascade? – securecurve May 23 '18 at 10:30
  • I think I know why. It means if the entity is merged, the related entity is merged too, which is not the case in this situation, because we only want to create a new Role, but we don't want to create/update a Permission. – securecurve May 23 '18 at 14:06
  • What if I'm not using Hibernate? – KareemJ Jan 02 '21 at 16:54
31

The correct solution would have been to upgrade to hibernate 4.2.15 / 4.3.6 or above and add the following lines to your persistence.xml:

<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>

Suraj Menon
  • 1,486
  • 3
  • 28
  • 50
  • 17
    This property applies to the entire persistent context and should only be used for testing purposes. If you set it to "allow" or "log", Hibernate will proceed with merging both the detached entities sequentially. However the order of the merge is not defined. So this can cause accidental data corruption. The correct solution is to fix the entity relationship. – VHS Nov 21 '16 at 20:14
  • 4
    @VHS can you explain what happens if I remove `CascadeType.MERGE`? I see it as the answer everywhere, but I *bet* it is a breaking change with side effects. – El Mac May 16 '18 at 11:02
  • @ElMac without `CascadeType.MERGE`, if you save an object that has a reference to another, you need to manually also store that other object; with `CascadeType.MERGE`, on the other hand, Hibernate does it for you automatically. So you are correct, this might cause other problems. – marcotama Mar 11 '21 at 23:25
27

Check your equals and hashCode method, ensure that it is consistent and correctly defined. For example I had copied and mistakenly pasted another-class when computing hashCode, this caused the object never to be equal with itself :(.

user1523177
  • 451
  • 5
  • 5
  • 2
    Great answer! Thank You! IntelliJ has a procedure for generating `equals` and `hashCode`, You can check it out [on their website](https://www.jetbrains.com/help/idea/generating-equals-and-hashcode.html). – Aleksandar Jun 20 '17 at 08:34
  • 1
    This helped! I'm using Lombok's Data annotation to generate all my additional methods, when changed to Getter Setter instead of @Data the problem has gone. Thank you. – SP5RFD Jul 25 '17 at 07:26
  • `equals` and `hashCode` of the parent entity or the detached entity? – KareemJ Jan 02 '21 at 17:39
22

Like others who based their answers on HHH-9106 but, because I'm using Spring Boot with Java-based annotation, I had to use the following in application.properties:

spring.jpa.properties.hibernate.event.merge.entity_copy_observer=allow
GuiRitter
  • 697
  • 1
  • 11
  • 20
15

I ran into the same problem too and solved it by add a few configs in application.yaml files.

  jpa:
    properties:
      hibernate:
        enable_lazy_load_no_trans: true
        event:
          merge:
            entity_copy_observer: allow

See it here How to persist a new entity containing multiple identical instances of another unpersisted entity with spring-boot and JPA?

W.Man
  • 630
  • 8
  • 12
6

I could fix it by replacing

cascade = CascadeType.All

with

casecade={CascadeType.PERSIST,CascadeType.REMOVE}
Arul Rozario
  • 679
  • 1
  • 9
  • 20
0

For Hibernate see the workaround here HHH-9106.

  • 6
    Please quote the most relevant part of the link, in case the target site is unreachable or goes permanently offline. See [How do I write a good answer](http://stackoverflow.com/help/how-to-answer). – ByteHamster Feb 19 '15 at 17:14
  • Or in case, my network blocks some CSS files, the site is completely unreadable. – Stephan Nov 28 '16 at 17:30
  • The link is about the `hibernate.event.merge.entity_copy_observer` property, which is already (at the time of this writing) covered by other answers. – GuiRitter Dec 23 '19 at 12:59
0

In my case, moving the fetch operation and save operation in same @Transactional block solved the problem.

0

error occurs when we have multiple object of same time in HashSet.Possible due to incorrect hash function.Hashset check equality of object on the basis of hash function between two objects.

Way to debug

Just try to print hashset you will see multiple object of same type.

Solution::#

  • Use HashSet while defining one to many relationships.
  • Avoid using Lists.
  • Make sure your hash function should be correct.
Community
  • 1
  • 1
razi
  • 41
  • 4
0
**@LazyCollection(LazyCollectionOption.FALSE** 

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)

@JoinColumn(name = "translate_id")
Taslim Oseni
  • 6,086
  • 10
  • 44
  • 69
0

I fixed this issue by removing cascade = CascadeType.ALL in your case (cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})

My code source:

Before

@ManyToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(
    name = "link_module_parcour",
    joinColumns = {@JoinColumn(name = "module_id", referencedColumnName = "id")},
    inverseJoinColumns = {@JoinColumn(name = "parcour_id", referencedColumnName = "id")})
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@BatchSize(size = 20)
private Set<Parcour> parcours = new HashSet<>();

After

@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(
    name = "link_module_parcour",
    joinColumns = {@JoinColumn(name = "module_id", referencedColumnName = "id")},
    inverseJoinColumns = {@JoinColumn(name = "parcour_id", referencedColumnName = "id")})
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@BatchSize(size = 20)
private Set<Parcour> parcours = new HashSet<>();
Ousama
  • 2,176
  • 3
  • 21
  • 26
0

If you remove the cascade merge you won't be able to update the entity when updating the parent. The case will be right if you don't want to update the child, but if you want to update the child when updating the parent removing merge will only not show the error but the issue will still exist.

What happened with me: I got the same exception but I need Cascade.merge. After searching I found that some of the values I was using when creating the entity for the first time are updated and removed from the code but in the database, they still exist and when removing them from the database also work as expected.

To clarify the case: Let's say I have an enum('ACTIVE', 'NOT_ACTIVE', 'SUSPENDED') and the field using this enum is key, when updating the code and removing the NOT_ACTIVE we should alter the database table with the new values enum('ACTIVE', 'SUSPENDED')

0

I had similar issue and it is resolved when I replace CascadeType.All with {CascadeType.persist, CascadeType.remove}.

Let me know if it works.

Shrip
  • 101
  • 1
  • 6
0

We can also resolve that using CascadeType.DETACH . In this case, if we need to update something in Permission, we have to update Permession separately and not by updating the related entity!

-1

Just a note to say I am using Hibernate Core 4.3.8 in a Spring MVC application, based on Spring Core 4.1.6. The workaround:

<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>

Did not work for me. I needed to remove the CascadeType.MERGE in order to correctly populate an @ManyToMany. Not sure if newer versions of Hibernate have fixed this.

kleopatra
  • 51,061
  • 28
  • 99
  • 211
Beagle
  • 3
  • 2