HHH-18158, HHH-18251, HHH-18062 fix composite id handling

by rolling back HHH-15184

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-06-14 14:48:25 +02:00
parent b3d01730ce
commit 2b62eaa058
3 changed files with 113 additions and 33 deletions

View File

@ -377,7 +377,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
else {
if ( componentClass == Object.class ) {
// Object is not a valid component class, but that is what we get when using a type variable
component.getProperties().clear();
component.clearProperties();
}
else {
final Iterator<Property> propertyIterator = component.getPropertyIterator();

View File

@ -8,7 +8,6 @@ package org.hibernate.mapping;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@ -61,6 +60,7 @@ import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
import org.hibernate.usertype.CompositeUserType;
import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.toList;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.internal.util.StringHelper.qualify;
@ -108,10 +108,6 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
private QualifiedName structName;
private String[] structColumnNames;
private transient Class<?> componentClass;
// lazily computed based on 'properties' field: invalidate by setting to null when properties are modified
private transient List<Selectable> cachedSelectables;
// lazily computed based on 'properties' field: invalidate by setting to null when properties are modified
private transient List<Column> cachedColumns;
private transient Generator builtIdentifierGenerator;
@ -186,7 +182,6 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
}
propertyDeclaringClasses.put( p, declaringClass.getName() );
}
propertiesListModified();
}
public void addProperty(Property p) {
@ -200,11 +195,6 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
return null;
}
private void propertiesListModified() {
this.cachedSelectables = null;
this.cachedColumns = null;
}
@Override
public void addColumn(Column column) {
throw new UnsupportedOperationException("Cant add a column to a component");
@ -212,33 +202,26 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
@Override
public List<Selectable> getSelectables() {
if ( cachedSelectables == null ) {
final List<Selectable> selectables = properties.stream()
.flatMap( p -> p.getSelectables().stream() )
.collect( toList() );
if ( discriminator != null ) {
selectables.addAll( discriminator.getSelectables() );
}
cachedSelectables = selectables;
final List<Selectable> selectables = new ArrayList<>( properties.size() + 2 );
for ( Property property : properties ) {
selectables.addAll( property.getSelectables() );
}
return cachedSelectables;
if ( discriminator != null ) {
selectables.addAll( discriminator.getSelectables() );
}
return unmodifiableList( selectables );
}
@Override
public List<Column> getColumns() {
if ( cachedColumns != null ) {
return cachedColumns;
final List<Column> columns = new ArrayList<>( properties.size() + 2 );
for ( Property property : properties ) {
columns.addAll( property.getValue().getColumns() );
}
else {
final List<Column> columns = properties.stream()
.flatMap( p -> p.getValue().getColumns().stream() )
.collect( toList() );
if ( discriminator != null ) {
columns.addAll( discriminator.getColumns() );
}
this.cachedColumns = Collections.unmodifiableList( columns );
return cachedColumns;
if ( discriminator != null ) {
columns.addAll( discriminator.getColumns() );
}
return unmodifiableList( columns );
}
public boolean isEmbedded() {
@ -763,6 +746,10 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
return propertyNames;
}
public void clearProperties() {
properties.clear();
}
public static class StandardGenerationContextLocator
implements CompositeNestedGeneratedValueGenerator.GenerationContextLocator {
private final String entityName;
@ -909,7 +896,6 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
}
}
}
propertiesListModified();
return this.originalPropertyOrder = originalPropertyOrder;
}

View File

@ -0,0 +1,94 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.records;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
import jakarta.persistence.OneToMany;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.Set;
import static jakarta.persistence.CascadeType.MERGE;
import static jakarta.persistence.CascadeType.PERSIST;
import static jakarta.persistence.CascadeType.REMOVE;
@DomainModel( annotatedClasses = {
RecordIdClassTest2.MyParentEntity.class,
RecordIdClassTest2.MyChildEntity.class} )
@SessionFactory
public class RecordIdClassTest2 {
@Test
public void testPersist(SessionFactoryScope scope) {
scope.inTransaction( s-> {
MyParentEntity ue = new MyParentEntity("hello");
MyChildEntity uae = new MyChildEntity(ue, "world");
ue.children.add(uae);
s.persist(ue);
});
}
public record MyRecord(Long code, String qualifier) {}
@Entity
@IdClass(MyRecord.class)
public static class MyChildEntity {
@Id
Long code;
@Id
String qualifier;
String text;
@ManyToOne
@MapsId("code")
private MyParentEntity parent;
public MyChildEntity(MyParentEntity parent, String qualifier) {
this.parent = parent;
this.qualifier = qualifier;
}
MyChildEntity() {
}
}
@Entity
public static class MyParentEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long code;
String description;
@OneToMany(
cascade = {PERSIST, MERGE, REMOVE},
mappedBy = "parent",
orphanRemoval = true)
private Set<MyChildEntity> children = new HashSet<>();
public MyParentEntity(String description) {
this.description = description;
}
MyParentEntity() {
}
}
}