From 2b3450ecc72d5b443369bfccbfc5840d03f48275 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 3 May 2023 12:33:02 +0200 Subject: [PATCH] HHH-16370 Add test for issue --- .../mapkey/ManyToManyMapKeyTest.java | 266 ++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyMapKeyTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyMapKeyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyMapKeyTest.java new file mode 100644 index 0000000000..7a4afd6349 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyMapKeyTest.java @@ -0,0 +1,266 @@ +package org.hibernate.orm.test.manytomany.mapkey; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapKey; +import jakarta.persistence.Table; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +@DomainModel( + annotatedClasses = { + ManyToManyMapKeyTest.MapContainer.class, + ManyToManyMapKeyTest.MapKeyEntity.class, + ManyToManyMapKeyTest.MapValueEntity.class + } +) +@SessionFactory +@JiraKey("HHH-16370") +public class ManyToManyMapKeyTest { + + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + MapContainer container = session.find( MapContainer.class, 1l ); + session.remove( container ); + + container.getMap().keySet().stream().forEach( key-> { + session.remove( key ); + }); + } + ); + } + + @Test + public void testInsert(SessionFactoryScope scope) { + MapKeyEntity keyEntity = new MapKeyEntity( 2l, "first entity" ); + scope.inTransaction( + session -> { + MapContainer container = new MapContainer( 1l, "container" ); + + MapValueEntity valueEntity = new MapValueEntity( 3l, container, keyEntity, "1" ); + + container.add( keyEntity, valueEntity ); + + session.persist( container ); + session.persist( keyEntity ); + session.persist( valueEntity ); + } + ); + + scope.inTransaction( + session -> { + List mapContainers = session.createQuery( + "select mc from MapContainer mc", + MapContainer.class + ).list(); + assertThat( mapContainers.size() ).isEqualTo( 1 ); + MapContainer container = mapContainers.get( 0 ); + Map map = container.getMap(); + assertThat( map.size() ).isEqualTo( 1 ); + + MapValueEntity valueEntity = map.get( keyEntity ); + assertThat( valueEntity ).isNotNull(); + assertThat( valueEntity.getMapContainer() ).isSameAs( container ); + assertThat( map.keySet().size() ).isEqualTo( 1 ); + assertThat( valueEntity.getMapKey() ).isSameAs( map.keySet().iterator().next() ); + } + ); + + scope.inTransaction( + session -> { + List mapContainers = session.createQuery( + "select mc from MapContainer mc join fetch mc.map", + MapContainer.class + ).list(); + assertThat( mapContainers.size() ).isEqualTo( 1 ); + MapContainer container = mapContainers.get( 0 ); + Map map = container.getMap(); + assertThat( map.size() ).isEqualTo( 1 ); + + MapValueEntity valueEntity = map.get( keyEntity ); + assertThat( valueEntity ).isNotNull(); + assertThat( valueEntity.getMapContainer() ).isSameAs( container ); + assertThat( map.keySet().size() ).isEqualTo( 1 ); + assertThat( valueEntity.getMapKey() ).isSameAs( map.keySet().iterator().next() ); + } + ); + } + + @Test + public void testUpdate(SessionFactoryScope scope) { + MapKeyEntity keyEntity = new MapKeyEntity( 2l, "first entity" ); + scope.inTransaction( + session -> { + MapContainer container = new MapContainer( 1l, "container" ); + + MapValueEntity valueEntity = new MapValueEntity( 3l, container, keyEntity, "1" ); + + container.add( keyEntity, valueEntity ); + + session.persist( container ); + session.persist( keyEntity ); + session.persist( valueEntity ); + } + ); + + scope.inTransaction( + session -> { + List mapContainers = session.createQuery( + "select mc from MapContainer mc", + MapContainer.class + ).list(); + assertThat( mapContainers.size() ).isEqualTo( 1 ); + MapContainer container = mapContainers.get( 0 ); + + MapValueEntity toRemove = container.getMap().get( keyEntity ); + session.remove( toRemove ); + + container.getMap().remove( keyEntity ); + + session.flush(); + + MapValueEntity valueEntity = new MapValueEntity( 4l, container, keyEntity, "2" ); + session.persist( valueEntity ); + + container.add( keyEntity, valueEntity ); + } + ); + } + + @Entity(name = "MapContainer") + @Table(name = "map_container") + public static class MapContainer { + @Id + private Long id; + + private String name; + + @ManyToMany(cascade = CascadeType.REMOVE) + @MapKey(name = "mapKey") + private Map map = new HashMap<>(); + + public MapContainer() { + } + + public MapContainer(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public Map getMap() { + return map; + } + + public void add(MapKeyEntity key, MapValueEntity entity) { + this.map.put( key, entity ); + } + } + + @Entity(name = "MapKeyEntity") + @Table(name = "map_key_entity") + public static class MapKeyEntity { + @Id + private Long id; + + private String name; + + public MapKeyEntity() { + } + + public MapKeyEntity(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + MapKeyEntity keyEntity = (MapKeyEntity) o; + return Objects.equals( id, keyEntity.id ) && Objects.equals( name, keyEntity.name ); + } + + @Override + public int hashCode() { + return Objects.hash( id, name ); + } + } + + @Entity(name = "MapValueEntity") + @Table(name = "map_value_entity") + public static class MapValueEntity { + @Id + private Long id; + + @ManyToOne(optional = false) + private MapContainer mapContainer; + + @ManyToOne(optional = false) + @JoinColumn(unique = true) + private MapKeyEntity mapKey; + + private String name; + + public MapValueEntity() { + } + + public MapValueEntity(Long id, MapContainer mapContainer, MapKeyEntity mapKey, String name) { + this.id = id; + this.mapContainer = mapContainer; + this.mapKey = mapKey; + this.name = name; + } + + public Long getId() { + return id; + } + + public MapContainer getMapContainer() { + return mapContainer; + } + + public MapKeyEntity getMapKey() { + return mapKey; + } + } +}