diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java index a872856065..6564f902bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java @@ -13,8 +13,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -49,7 +49,6 @@ import org.hibernate.mapping.Collection; import org.hibernate.mapping.Column; import org.hibernate.mapping.Component; import org.hibernate.mapping.Join; -import org.hibernate.mapping.JoinedSubclass; import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; @@ -437,7 +436,7 @@ public class BinderHelper { final String name = collector.getPhysicalColumnName( referencedTable, joinColumn.getReferencedColumn() ); final Column column = new Column( name ); orderedColumns.add( column ); - columnsToProperty.put( column, new HashSet<>() ); + columnsToProperty.put( column, new LinkedHashSet<>() ); //need to use a LinkedHashSet here to make it deterministic } // Now, for each column find the properties of the target entity @@ -520,7 +519,6 @@ public class BinderHelper { } else { // we have the first column of a new property - orderedProperties.add( property ); if ( property.getColumnSpan() > 1 ) { if ( !property.getColumns().get(0).equals( column ) ) { // the columns have to occur in the right order in the property @@ -531,6 +529,7 @@ public class BinderHelper { currentProperty = property; lastPropertyColumnIndex = 1; } + orderedProperties.add( property ); } break; // we're only considering the first matching property for now } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cuk/JoinColumnOccursOutOfOrderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cuk/JoinColumnOccursOutOfOrderTest.java new file mode 100644 index 0000000000..22ae74206b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cuk/JoinColumnOccursOutOfOrderTest.java @@ -0,0 +1,202 @@ +package org.hibernate.orm.test.cuk;//package com.example.demo; + +import jakarta.persistence.*; +import org.hibernate.annotations.DynamicUpdate; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +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.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +@SessionFactory +@DomainModel(annotatedClasses = { + JoinColumnOccursOutOfOrderTest.MasterEntity.class, + JoinColumnOccursOutOfOrderTest.ChildTwoEntity.class, + JoinColumnOccursOutOfOrderTest.ChildEntityOne.class, + JoinColumnOccursOutOfOrderTest.ChildEntityFour.class, + JoinColumnOccursOutOfOrderTest.ChildEntityThree.class, +}) +@JiraKey("HHH-16263") +public class JoinColumnOccursOutOfOrderTest { + + @BeforeAll + public void setUp(SessionFactoryScope scope) { + scope.inTransaction( session -> { + var meta = new MasterEntity(); + meta.setId(1l); + meta.column1 = "1"; + meta.column2 = "2"; + meta.column3 = "3"; + session.persist( meta ); + } ); + } + + @AfterAll + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( session -> { + } ); + } + + @Test + public void testOutOffOrder(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final var container = session.createQuery( + "from MasterEntity container where container.id = :param ", + MasterEntity.class + ).setParameter("param", 1).getSingleResult(); + } ); + } + + @Embeddable + public static class ChildOneId implements Serializable { + + @Column(name = "COLUMN_1", nullable = false, length = 7) + private String column1; + + @Column(name = "COLUMN_2", nullable = false, length = 4) + private String column2; + + @Column(name = "COLUMN_3", nullable = false, length = 2) + private String column3; + } + + @Embeddable + public static class ChildTwoId implements Serializable { + + @Column(name = "COLUMN_1", length = 7, nullable = false) + private String column1; + @Column(name = "COLUMN_2", length = 4, nullable = false) + private String column2; + @Column(name = "COLUMN_3", length = 2, nullable = false) + private String column3; + + } + + @Embeddable + public static class ChildThreeId implements Serializable { + + @Column(name = "COLUMN_1", nullable = false, length = 7) + private String column1; + + @Column(name = "COLUMN_2", nullable = false, length = 4) + private String column2; + + @Column(name = "COLUMN_3", nullable = false, length = 2) + private String column3; + + @Column(name = "COLUMN_4", nullable = false) + private LocalDateTime creation; + + } + + @Embeddable + public static class ChildFourId implements Serializable { + + @Column(name = "COLUMN_1", length = 7, nullable = false) + private String column1; + + @Column(name = "COLUMN_2", length = 4, nullable = false) + private String colum2; + + @Column(name = "COLUMN_3", length = 2, nullable = false) + private String column3; + + @Column(name = "NON_UNIQUE_ID", nullable = false) + private Long nonUNiqueId; + + @Column(name = "COLUMN_4", nullable = false) + private LocalDateTime creation; + + } + + @Entity + public static class ChildEntityFour { + @EmbeddedId + private ChildFourId id; + } + + @Entity + public static class ChildEntityOne { + @EmbeddedId + private ChildOneId id; + } + + @Entity + @DynamicUpdate + public static class ChildTwoEntity { + @EmbeddedId + private ChildTwoId id; + } + + @Entity + public static class ChildEntityThree { + @EmbeddedId + private ChildThreeId id; + } + + + @Entity(name = "MasterEntity") + public static class MasterEntity { + + @Id + @Column(name = "ID", unique = true, nullable = false) + private Long id; + + @Column(name = "COLUMN_1", nullable = false, length = 7) + private String column1; + + @Column(name = "COLUMN_2", nullable = false, length = 4) + private String column2; + + @Column(name = "COLUMN_3", nullable = false, length = 2) + private String column3; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumns(foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT), value = { + @JoinColumn(name = "COLUMN_1", referencedColumnName = "COLUMN_1", insertable = false, updatable = false), + @JoinColumn(name = "COLUMN_2", referencedColumnName = "COLUMN_2", insertable = false, updatable = false), + @JoinColumn(name = "COLUMN_3", referencedColumnName = "COLUMN_3", insertable = false, updatable = false) + }) + @NotFound(action = NotFoundAction.IGNORE) + private ChildEntityOne childEntityOne; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumns(foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT), value = { + @JoinColumn(name = "COLUMN_1", referencedColumnName = "COLUMN_1", insertable = false, updatable = false), + @JoinColumn(name = "COLUMN_2", referencedColumnName = "COLUMN_2", insertable = false, updatable = false), + @JoinColumn(name = "COLUMN_3", referencedColumnName = "COLUMN_3", insertable = false, updatable = false) + }) + @NotFound(action = NotFoundAction.IGNORE) + private ChildTwoEntity childEntityTwo; + + @OneToMany(fetch = FetchType.LAZY) + @JoinColumn(name = "COLUMN_1", referencedColumnName = "COLUMN_1", insertable = false, updatable = false) + @JoinColumn(name = "COLUMN_2", referencedColumnName = "COLUMN_2", insertable = false, updatable = false) + @JoinColumn(name = "COLUMN_3", referencedColumnName = "COLUMN_3", insertable = false, updatable = false) + private List childEntityThree; + + @OneToMany(fetch = FetchType.LAZY) + @JoinColumn(name = "COLUMN_1", referencedColumnName = "COLUMN_1", insertable = false, updatable = false) + @JoinColumn(name = "COLUMN_2", referencedColumnName = "COLUMN_2", insertable = false, updatable = false) + @JoinColumn(name = "COLUMN_3", referencedColumnName = "COLUMN_3", insertable = false, updatable = false) + private List childEntityFour; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + } + +}