Skip to content

Commit 2b62eaa

Browse files
committed
HHH-18158, HHH-18251, HHH-18062 fix composite id handling
by rolling back HHH-15184 Signed-off-by: Gavin King <[email protected]>
1 parent b3d0173 commit 2b62eaa

File tree

3 files changed

+113
-33
lines changed

3 files changed

+113
-33
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/internal/ClassPropertyHolder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ public void doSecondPass(Map persistentClasses) throws MappingException {
377377
else {
378378
if ( componentClass == Object.class ) {
379379
// Object is not a valid component class, but that is what we get when using a type variable
380-
component.getProperties().clear();
380+
component.clearProperties();
381381
}
382382
else {
383383
final Iterator<Property> propertyIterator = component.getPropertyIterator();

hibernate-core/src/main/java/org/hibernate/mapping/Component.java

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import java.lang.reflect.Constructor;
1010
import java.util.ArrayList;
11-
import java.util.Collections;
1211
import java.util.Comparator;
1312
import java.util.HashMap;
1413
import java.util.HashSet;
@@ -61,6 +60,7 @@
6160
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
6261
import org.hibernate.usertype.CompositeUserType;
6362

63+
import static java.util.Collections.unmodifiableList;
6464
import static java.util.stream.Collectors.toList;
6565
import static org.hibernate.generator.EventType.INSERT;
6666
import static org.hibernate.internal.util.StringHelper.qualify;
@@ -108,10 +108,6 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
108108
private QualifiedName structName;
109109
private String[] structColumnNames;
110110
private transient Class<?> componentClass;
111-
// lazily computed based on 'properties' field: invalidate by setting to null when properties are modified
112-
private transient List<Selectable> cachedSelectables;
113-
// lazily computed based on 'properties' field: invalidate by setting to null when properties are modified
114-
private transient List<Column> cachedColumns;
115111

116112
private transient Generator builtIdentifierGenerator;
117113

@@ -186,7 +182,6 @@ public void addProperty(Property p, XClass declaringClass) {
186182
}
187183
propertyDeclaringClasses.put( p, declaringClass.getName() );
188184
}
189-
propertiesListModified();
190185
}
191186

192187
public void addProperty(Property p) {
@@ -200,45 +195,33 @@ public String getPropertyDeclaringClass(Property p) {
200195
return null;
201196
}
202197

203-
private void propertiesListModified() {
204-
this.cachedSelectables = null;
205-
this.cachedColumns = null;
206-
}
207-
208198
@Override
209199
public void addColumn(Column column) {
210200
throw new UnsupportedOperationException("Cant add a column to a component");
211201
}
212202

213203
@Override
214204
public List<Selectable> getSelectables() {
215-
if ( cachedSelectables == null ) {
216-
final List<Selectable> selectables = properties.stream()
217-
.flatMap( p -> p.getSelectables().stream() )
218-
.collect( toList() );
219-
if ( discriminator != null ) {
220-
selectables.addAll( discriminator.getSelectables() );
221-
}
222-
cachedSelectables = selectables;
205+
final List<Selectable> selectables = new ArrayList<>( properties.size() + 2 );
206+
for ( Property property : properties ) {
207+
selectables.addAll( property.getSelectables() );
208+
}
209+
if ( discriminator != null ) {
210+
selectables.addAll( discriminator.getSelectables() );
223211
}
224-
return cachedSelectables;
212+
return unmodifiableList( selectables );
225213
}
226214

227215
@Override
228216
public List<Column> getColumns() {
229-
if ( cachedColumns != null ) {
230-
return cachedColumns;
217+
final List<Column> columns = new ArrayList<>( properties.size() + 2 );
218+
for ( Property property : properties ) {
219+
columns.addAll( property.getValue().getColumns() );
231220
}
232-
else {
233-
final List<Column> columns = properties.stream()
234-
.flatMap( p -> p.getValue().getColumns().stream() )
235-
.collect( toList() );
236-
if ( discriminator != null ) {
237-
columns.addAll( discriminator.getColumns() );
238-
}
239-
this.cachedColumns = Collections.unmodifiableList( columns );
240-
return cachedColumns;
221+
if ( discriminator != null ) {
222+
columns.addAll( discriminator.getColumns() );
241223
}
224+
return unmodifiableList( columns );
242225
}
243226

244227
public boolean isEmbedded() {
@@ -763,6 +746,10 @@ public String[] getPropertyNames() {
763746
return propertyNames;
764747
}
765748

749+
public void clearProperties() {
750+
properties.clear();
751+
}
752+
766753
public static class StandardGenerationContextLocator
767754
implements CompositeNestedGeneratedValueGenerator.GenerationContextLocator {
768755
private final String entityName;
@@ -909,7 +896,6 @@ private int[] sortProperties(boolean forceRetainOriginalOrder) {
909896
}
910897
}
911898
}
912-
propertiesListModified();
913899
return this.originalPropertyOrder = originalPropertyOrder;
914900
}
915901

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.orm.test.records;
8+
9+
import jakarta.persistence.Entity;
10+
import jakarta.persistence.GeneratedValue;
11+
import jakarta.persistence.GenerationType;
12+
import jakarta.persistence.Id;
13+
import jakarta.persistence.IdClass;
14+
import jakarta.persistence.ManyToOne;
15+
import jakarta.persistence.MapsId;
16+
import jakarta.persistence.OneToMany;
17+
import org.hibernate.testing.orm.junit.DomainModel;
18+
import org.hibernate.testing.orm.junit.SessionFactory;
19+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
20+
import org.junit.jupiter.api.Test;
21+
22+
import java.util.HashSet;
23+
import java.util.Set;
24+
25+
import static jakarta.persistence.CascadeType.MERGE;
26+
import static jakarta.persistence.CascadeType.PERSIST;
27+
import static jakarta.persistence.CascadeType.REMOVE;
28+
29+
@DomainModel( annotatedClasses = {
30+
RecordIdClassTest2.MyParentEntity.class,
31+
RecordIdClassTest2.MyChildEntity.class} )
32+
@SessionFactory
33+
public class RecordIdClassTest2 {
34+
35+
@Test
36+
public void testPersist(SessionFactoryScope scope) {
37+
scope.inTransaction( s-> {
38+
MyParentEntity ue = new MyParentEntity("hello");
39+
MyChildEntity uae = new MyChildEntity(ue, "world");
40+
ue.children.add(uae);
41+
s.persist(ue);
42+
});
43+
}
44+
45+
public record MyRecord(Long code, String qualifier) {}
46+
47+
@Entity
48+
@IdClass(MyRecord.class)
49+
public static class MyChildEntity {
50+
51+
@Id
52+
Long code;
53+
54+
@Id
55+
String qualifier;
56+
57+
String text;
58+
59+
@ManyToOne
60+
@MapsId("code")
61+
private MyParentEntity parent;
62+
63+
public MyChildEntity(MyParentEntity parent, String qualifier) {
64+
this.parent = parent;
65+
this.qualifier = qualifier;
66+
}
67+
68+
MyChildEntity() {
69+
}
70+
}
71+
72+
@Entity
73+
public static class MyParentEntity {
74+
75+
@Id
76+
@GeneratedValue(strategy = GenerationType.IDENTITY)
77+
Long code;
78+
79+
String description;
80+
81+
@OneToMany(
82+
cascade = {PERSIST, MERGE, REMOVE},
83+
mappedBy = "parent",
84+
orphanRemoval = true)
85+
private Set<MyChildEntity> children = new HashSet<>();
86+
87+
public MyParentEntity(String description) {
88+
this.description = description;
89+
}
90+
91+
MyParentEntity() {
92+
}
93+
}
94+
}

0 commit comments

Comments
 (0)