diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java index a1f833b45e..d72f3dfd2a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java @@ -135,6 +135,15 @@ public class InferredBasicValueResolver { } } + if ( jdbcMapping == null ) { + throw new MappingException( + "Could not determine JavaTypeDescriptor nor SqlTypeDescriptor to use" + "" + + " for " + ( (BasicValue) stdIndicators ).getResolvedJavaClass() + + "; table = " + table.getName() + + "; column = " + selectable.getText() + ); + } + return new InferredBasicValueResolution( jdbcMapping, jdbcMapping.getJavaTypeDescriptor(), diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java index 2515973e95..186e48e408 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java @@ -167,6 +167,10 @@ public class BasicValue extends SimpleValue implements SqlTypeDescriptorIndicato return column; } + public Class getResolvedJavaClass() { + return resolvedJavaClass; + } + @Override public long getColumnLength() { if ( column != null && column instanceof Column ) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java index 39679bef66..66bb1331e2 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java @@ -42,6 +42,7 @@ import org.hibernate.metamodel.model.domain.internal.MapMember; import org.hibernate.metamodel.model.domain.internal.MappedSuperclassTypeImpl; import org.hibernate.metamodel.model.domain.internal.PluralAttributeBuilder; import org.hibernate.metamodel.model.domain.internal.SingularAttributeImpl; +import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; import org.hibernate.metamodel.spi.ManagedTypeRepresentationStrategy; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.property.access.internal.PropertyAccessMapImpl; @@ -244,7 +245,7 @@ public class AttributeFactory { .getJavaTypeDescriptorRegistry(); final JavaTypeDescriptor javaTypeDescriptor = registry.resolveDescriptor( embeddableClass ); - final ManagedTypeRepresentationStrategy representationStrategy = context.getTypeConfiguration() + final EmbeddableRepresentationStrategy representationStrategy = context.getTypeConfiguration() .getMetadataBuildingContext() .getBuildingOptions() .getManagedTypeRepresentationResolver() diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java index d81ec4b681..279384c1ac 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java @@ -347,6 +347,9 @@ public class EmbeddableMappingType implements ManagedMappingType { TypeConfiguration typeConfiguration) { attributeMappings.forEach( (s, attributeMapping) -> { + if ( attributeMapping instanceof PluralAttributeMapping ) { + return; + } if ( attributeMapping instanceof ToOneAttributeMapping ) { ( (ToOneAttributeMapping) attributeMapping ).getKeyTargetMatchPart().visitJdbcTypes( action, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java index 0a0cfc08df..1eaf2ecb08 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java @@ -275,6 +275,14 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa return this; } + @Override + public Object disassemble(Object value, SharedSessionContractImplementor session) { + if ( value == null ) { + return null; + } + return propertyAccess.getGetter().get( value ); + } + @Override public Fetch generateFetch( FetchParent fetchParent, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java index 68149d6b38..15a9b528de 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java @@ -40,12 +40,14 @@ import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.from.CompositeTableGroup; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroupJoin; +import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchOptions; import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl; +import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.spi.TypeConfiguration; @@ -92,6 +94,20 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF this.sqlAliasStem = sqlAliasStem; } + @Override + public DomainResult createDomainResult( + NavigablePath navigablePath, + TableGroup tableGroup, + String resultVariable, + DomainResultCreationState creationState) { + return new EmbeddableResultImpl<>( + navigablePath, + this, + resultVariable, + creationState + ); + } + @Override public Nature getNature() { return nature; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java index eccc57e8fb..1be37e14ba 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java @@ -11,6 +11,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -44,8 +46,8 @@ public abstract class AbstractManagedType private final ManagedDomainType superType; private final RepresentationMode representationMode; - private final Map> declaredSingularAttributes = new HashMap<>(); - private final Map> declaredPluralAttributes = new HashMap<>(); + private final Map> declaredSingularAttributes = new LinkedHashMap<>(); + private final Map> declaredPluralAttributes = new LinkedHashMap<>(); private final List subTypes = new ArrayList<>(); @@ -104,7 +106,7 @@ public abstract class AbstractManagedType @Override @SuppressWarnings("unchecked") public Set> getAttributes() { - final HashSet attributes = new HashSet<>( getDeclaredAttributes() ); + final HashSet attributes = new LinkedHashSet( getDeclaredAttributes() ); if ( getSuperType() != null ) { attributes.addAll( getSuperType().getAttributes() ); @@ -120,7 +122,7 @@ public abstract class AbstractManagedType return Collections.emptySet(); } - final HashSet attributes = new HashSet<>( declaredSingularAttributes.values() ); + final HashSet attributes = new LinkedHashSet( declaredSingularAttributes.values() ); attributes.addAll( declaredPluralAttributes.values() ); return attributes; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/EmbeddableDomainType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/EmbeddableDomainType.java index 294bdfafb9..34719000e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/EmbeddableDomainType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/EmbeddableDomainType.java @@ -18,6 +18,6 @@ import org.hibernate.metamodel.spi.ManagedTypeRepresentationStrategy; * * @author Steve Ebersole */ -public interface EmbeddableDomainType extends ManagedDomainType, EmbeddableType { +public interface EmbeddableDomainType extends ManagedDomainType, EmbeddableType, AllowableParameterType { ManagedTypeRepresentationStrategy getRepresentationStrategy(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java index 4e3baf2e8c..d32f50d313 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java @@ -7,16 +7,31 @@ package org.hibernate.metamodel.model.domain.internal; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import javax.persistence.metamodel.Attribute; import org.hibernate.NotYetImplementedFor6Exception; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.internal.SubGraphImpl; import org.hibernate.graph.spi.SubGraphImplementor; +import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.model.domain.AbstractManagedType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.JpaMetamodel; +import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; import org.hibernate.metamodel.spi.ManagedTypeRepresentationStrategy; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.property.access.internal.PropertyAccessStrategyMixedImpl; +import org.hibernate.property.access.spi.PropertyAccess; +import org.hibernate.sql.ast.Clause; +import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.spi.TypeConfiguration; /** * Standard Hibernate implementation of JPA's {@link javax.persistence.metamodel.EmbeddableType} @@ -27,13 +42,13 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; */ public class EmbeddableTypeImpl extends AbstractManagedType - implements EmbeddableDomainType, Serializable { + implements EmbeddableDomainType, Serializable, MappingModelExpressable { - private final ManagedTypeRepresentationStrategy representationStrategy; + private final EmbeddableRepresentationStrategy representationStrategy; public EmbeddableTypeImpl( JavaTypeDescriptor javaTypeDescriptor, - ManagedTypeRepresentationStrategy representationStrategy, + EmbeddableRepresentationStrategy representationStrategy, JpaMetamodel domainMetamodel) { super( javaTypeDescriptor.getJavaType().getName(), javaTypeDescriptor, null, domainMetamodel ); this.representationStrategy = representationStrategy; @@ -71,4 +86,75 @@ public class EmbeddableTypeImpl public SubGraphImplementor makeSubGraph(Class subType) { return new SubGraphImpl( this, true, jpaMetamodel() ); } + + @Override + public void visitJdbcValues( + Object value, Clause clause, JdbcValuesConsumer valuesConsumer, SharedSessionContractImplementor session) { + Object[] disassemble = (Object[]) disassemble( value, session ); + + List jdbcMappings = getJdbcMappings( session.getFactory().getTypeConfiguration() ); + for ( int i = 0; i < disassemble.length; i++ ) { + valuesConsumer.consume( disassemble[i], jdbcMappings.get( i ) ); + } + } + + @Override + public void visitJdbcTypes( + Consumer action, + Clause clause, + TypeConfiguration typeConfiguration) { + Set> attributes = getAttributes(); + + for ( Attribute attribute : attributes ) { + if ( attribute instanceof SingularAttributeImpl ) { + if ( attribute.isAssociation() ) { + EntityTypeImpl entityType = (EntityTypeImpl) ( (SingularAttributeImpl) attribute ).getValueGraphType(); + + BasicType basicType = jpaMetamodel().getTypeConfiguration() + .getBasicTypeForJavaType( entityType.findIdAttribute().getJavaType() ); + action.accept( basicType.getJdbcMapping() ); + } + else { + BasicType basicType = jpaMetamodel().getTypeConfiguration() + .getBasicTypeForJavaType( attribute.getJavaType() ); + action.accept( basicType.getJdbcMapping() ); + } + } + } + } + + @Override + public Object disassemble(Object value, SharedSessionContractImplementor session) { + final Set> attributes = getAttributes(); + final List result = new ArrayList<>(); + for ( Attribute attribute : attributes ) { + if ( attribute instanceof SingularAttributeImpl ) { + final PropertyAccess propertyAccess = PropertyAccessStrategyMixedImpl.INSTANCE + .buildPropertyAccess( getJavaType(), attribute.getName() ); + + final Object attributeValue = propertyAccess.getGetter().get( value ); + if ( attribute.isAssociation() ) { + final EntityPersister entityDescriptor = session.getFactory().getMetamodel() + .findEntityDescriptor( attribute.getJavaType().getName() ); + final Object disassembled = entityDescriptor.getIdentifierMapping().disassemble( + attributeValue, + session + ); + if ( disassembled instanceof Object[] ) { + for ( Object o : (Object[]) disassembled ) { + result.add( o ); + } + } + else { + result.add( disassembled ); + } + } + else { + result.add( attributeValue ); + } + } + } + return result.toArray(); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java index 8015eb3276..8a362ab734 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java @@ -712,6 +712,10 @@ public class MappingMetamodelImpl implements MappingMetamodel, MetamodelImplemen throw new NotYetImplementedFor6Exception( "Resolution of embedded-valued SqmExpressable nodes not yet implemented" ); } + if ( sqmExpressable instanceof EmbeddableTypeImpl ) { + return (MappingModelExpressable) sqmExpressable; + } + throw new UnsupportedOperationException( "Cannot determine proper mapping model expressable for " + sqmExpressable ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index 2694d18ece..82f16a55a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -29,7 +29,6 @@ import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart; import org.hibernate.metamodel.mapping.internal.EntityCollectionPart; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableParameterType; @@ -2178,25 +2177,17 @@ public abstract class BaseSqmToSqlAstConverter @Override public MemberOfPredicate visitMemberOfPredicate(SqmMemberOfPredicate predicate) { final SqmPath pluralPath = predicate.getPluralPath(); - final PluralAttributeMapping mappingModelExpressable = (PluralAttributeMapping) SqmMappingModelHelper.resolveMappingModelExpressable( - pluralPath, - getCreationContext().getDomainModel(), - getFromClauseAccess()::findTableGroup - ); + final PluralAttributeMapping mappingModelExpressable = (PluralAttributeMapping) determineValueMapping(pluralPath); - final CollectionPart elementDescriptor = mappingModelExpressable.getElementDescriptor(); - - if ( elementDescriptor instanceof EntityCollectionPart ) { + if ( mappingModelExpressable.getElementDescriptor() instanceof EntityCollectionPart ) { inferableTypeAccessStack.push( - () -> ( (EntityCollectionPart) elementDescriptor ).getEntityMappingType().getIdentifierMapping() ); - } - else if ( elementDescriptor instanceof BasicValuedCollectionPart ) { - inferableTypeAccessStack.push( () -> elementDescriptor ); + () -> ( (EntityCollectionPart) mappingModelExpressable.getElementDescriptor() ).getEntityMappingType() + .getIdentifierMapping() ); } else { - throw new NotYetImplementedFor6Exception( - "Member of with Collection of Embeddable has not yet been implemented" ); + inferableTypeAccessStack.push( () -> mappingModelExpressable ); } + final Expression lhs; try { lhs = (Expression) predicate.getLeftHandExpression().accept( this ); @@ -2234,6 +2225,8 @@ public abstract class BaseSqmToSqlAstConverter creationContext ); + fromClauseIndex.registerTableGroup( pluralPath.getNavigablePath(), rootTableGroup ); + querySpec.getFromClause().addRoot( rootTableGroup ); final CollectionPart elementDescriptor = mappingModelExpressable.getElementDescriptor(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/collectionelement/EmbeddableElementCollectionMemberOfTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/collectionelement/EmbeddableElementCollectionMemberOfTest.java new file mode 100644 index 0000000000..ee59dde36e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/collectionelement/EmbeddableElementCollectionMemberOfTest.java @@ -0,0 +1,145 @@ +package org.hibernate.orm.test.annotations.collectionelement; + +import java.util.HashSet; +import java.util.Set; +import javax.persistence.ElementCollection; +import javax.persistence.Embeddable; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToOne; + +import org.hibernate.query.spi.QueryImplementor; + +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; + +/** + * @author Andrea Boriero + */ +@DomainModel(annotatedClasses = { + EmbeddableElementCollectionMemberOfTest.Person.class, + EmbeddableElementCollectionMemberOfTest.City.class +}) +@SessionFactory +public class EmbeddableElementCollectionMemberOfTest { + + @Test + public void testMemberOfQuery(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + Address a = new Address(); + a.setStreet( "Lollard Street" ); + QueryImplementor query = session.createQuery( "from Person p where :address member of p.addresses" ); + query.setParameter( "address", a ); + query.list(); + } + ); + } + + @Entity(name = "Person") + public static class Person { + private Long id; + private String name; + private Set
addresses = new HashSet<>(); + private Address address; + + @Id + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @ElementCollection + @JoinTable( + name = "addresses", + joinColumns = @JoinColumn(name = "PERSON_ID")) + public Set
getAddresses() { + return addresses; + } + + public void setAddresses(Set
addresses) { + this.addresses = addresses; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + } + + @Embeddable + public static class Address { + public String street; + public int number; + + public City city; + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public int getNumber() { + return number; + } + + public void setNumber(int number) { + this.number = number; + } + + @ManyToOne + public City getCity() { + return city; + } + + public void setCity(City city) { + this.city = city; + } + } + + @Entity(name = "City") + public static class City { + + private Long id; + + private String name; + + @Id + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/EagerManyToOneEmbeddedIdFKTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/EagerManyToOneEmbeddedIdFKTest.java index 7a1bd91f95..292d418b7c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/EagerManyToOneEmbeddedIdFKTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/EagerManyToOneEmbeddedIdFKTest.java @@ -128,7 +128,6 @@ public class EagerManyToOneEmbeddedIdFKTest { } @Test - @FailureExpected(reason = "Embedded parameters has not yet been implemented ") public void testEmbeddedIdParameter(SessionFactoryScope scope) { scope.inTransaction( session -> { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/ManyToOneEmbeddedIdWithToOneFKTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/ManyToOneEmbeddedIdWithToOneFKTest.java index 1bceefa684..1df9ee4da0 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/ManyToOneEmbeddedIdWithToOneFKTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/ManyToOneEmbeddedIdWithToOneFKTest.java @@ -19,7 +19,6 @@ import org.hibernate.Hibernate; import org.hibernate.testing.jdbc.SQLStatementInspector; import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.FailureExpected; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.junit.jupiter.api.AfterEach; @@ -150,7 +149,6 @@ public class ManyToOneEmbeddedIdWithToOneFKTest { } @Test - @FailureExpected(reason = "Embedded parameters has not yet been implemented ") public void testEmbeddedIdParameter(SessionFactoryScope scope) { scope.inTransaction( session -> { @@ -159,7 +157,7 @@ public class ManyToOneEmbeddedIdWithToOneFKTest { PK superUserKey = new PK( dataCenter, "Fab" ); System system = session.createQuery( - "from System e join fetch e.user u where u.id = :id", + "from System e join fetch e.dataCenterUser u where u.id = :id", System.class ).setParameter( "id", superUserKey ).uniqueResult(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/OneToManyEmbeddedIdFKTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/OneToManyEmbeddedIdFKTest.java index f13a937456..981c29ce35 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/OneToManyEmbeddedIdFKTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/OneToManyEmbeddedIdFKTest.java @@ -123,7 +123,6 @@ public class OneToManyEmbeddedIdFKTest { } @Test - @FailureExpected(reason = "Embedded parameters has not yet been implemented ") public void testEmbeddedIdParameter(SessionFactoryScope scope) { scope.inTransaction( session -> { @@ -135,7 +134,7 @@ public class OneToManyEmbeddedIdFKTest { ).setParameter( "id", superUserKey ).uniqueResult(); assertThat( system, is( notNullValue() ) ); - assertThat( system.getUsers().size(), is( 2 ) ); + assertThat( system.getUsers().size(), is( 1 ) ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EmbeddableAsParameterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EmbeddableAsParameterTest.java index 74ef60d7c8..14899f974b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EmbeddableAsParameterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EmbeddableAsParameterTest.java @@ -10,9 +10,11 @@ import java.util.List; import javax.persistence.Embeddable; import javax.persistence.Entity; import javax.persistence.Id; +import javax.persistence.OneToMany; -import org.hibernate.testing.junit5.SessionFactoryBasedFunctionalTest; -import org.hibernate.testing.orm.junit.FailureExpected; +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.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -23,19 +25,18 @@ import static org.hamcrest.MatcherAssert.assertThat; /** * @author Andrea Boriero */ -@FailureExpected( reason = "Support for embedded-valued parameters not yet implemented" ) -public class EmbeddableAsParameterTest extends SessionFactoryBasedFunctionalTest { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Person.class, - }; - } +@DomainModel( + annotatedClasses = { + EmbeddableAsParameterTest.Person.class, + EmbeddableAsParameterTest.EntityTest.class + } +) +@SessionFactory +public class EmbeddableAsParameterTest { @Test - public void testAsParameterInWhereClause() { - inTransaction( + public void testAsParameterInWhereClause(SessionFactoryScope scope) { + scope.inTransaction( session -> { List results = session.createQuery( "select p from Person p where p.name = :name" ). setParameter( "name", new Name( "Fab", "Fab" ) ).list(); @@ -45,19 +46,32 @@ public class EmbeddableAsParameterTest extends SessionFactoryBasedFunctionalTest } @Test - public void testAsParameterReuseInWhereClause() { - inTransaction( + public void testAsParameterReuseInWhereClause(SessionFactoryScope scope) { + scope.inTransaction( session -> { - List results = session.createQuery( "select p from Person p where p.name = :name or p.name = :name " ). - setParameter( "name", new Name( "Fab", "Fab" ) ).list(); + List results = session.createQuery( "select p from Person p where p.name = :name or p.name = :name " ) + . + setParameter( "name", new Name( "Fab", "Fab" ) ) + .list(); assertThat( results.size(), is( 1 ) ); } ); } + @Test + public void testAsParameterReuseInWhereClause2(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + List results = session.createQuery( "select p from Person p where p.embeddableTest = :embeddable" ). + setParameter( "embeddable", new EmbeddableTest() ).list(); + assertThat( results.size(), is( 0 ) ); + } + ); + } + @BeforeEach - public void setUp() { - inTransaction( + public void setUp(SessionFactoryScope scope) { + scope.inTransaction( session -> { Person person = new Person( 1, @@ -70,8 +84,8 @@ public class EmbeddableAsParameterTest extends SessionFactoryBasedFunctionalTest } @AfterEach - public void tearDown() { - inTransaction( + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( session -> { session.createQuery( "delete Person" ).executeUpdate(); } @@ -85,6 +99,8 @@ public class EmbeddableAsParameterTest extends SessionFactoryBasedFunctionalTest private Name name; + private EmbeddableTest embeddableTest; + private Integer age; public Person() { @@ -124,6 +140,46 @@ public class EmbeddableAsParameterTest extends SessionFactoryBasedFunctionalTest public void setAge(Integer age) { this.age = age; } + + public EmbeddableTest getEmbeddableTest() { + return embeddableTest; + } + + public void setEmbeddableTest(EmbeddableTest embeddableTest) { + this.embeddableTest = embeddableTest; + } + } + + @Embeddable + public static class EmbeddableTest { + private String street; + + @OneToMany + private List entityTests; + + } + + @Entity(name = "EmbeddableTest") + public static class EntityTest { + @Id + private Long id; + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EmbeddableWithPluralAttributeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EmbeddableWithPluralAttributeTest.java new file mode 100644 index 0000000000..1f309000ff --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EmbeddableWithPluralAttributeTest.java @@ -0,0 +1,114 @@ +package org.hibernate.orm.test.query.hql; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Embeddable; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.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.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + + +/** + * @author Andrea Boriero + */ +@DomainModel( + annotatedClasses = { + EmbeddableWithPluralAttributeTest.A.class, + EmbeddableWithPluralAttributeTest.C.class + } +) +@SessionFactory +public class EmbeddableWithPluralAttributeTest { + + + @BeforeAll + public void setUp(SessionFactoryScope scope){ + scope.inTransaction( + session -> { + A a = new A(); + a.id = 1; + + B b = B.buildB(); + a.b = b; + + session.save( a ); + } + ); + } + + @Test + public void testAsParameterReuseInWhereClauseZeroResults(SessionFactoryScope scope) { + + scope.inTransaction( + session -> { + List results = session.createQuery( "select a from A a where a.b = :b" ). + setParameter( "b", new B() ).list(); + assertThat( results.size(), is( 0 ) ); + } + ); + } + + @Test + public void testAsParameterReuseInWhereClause(SessionFactoryScope scope) { + + scope.inTransaction( + session -> { + List results = session.createQuery( "select a from A a where a.b = :b" ). + setParameter( "b", B.buildB() ).list(); + assertThat( results.size(), is( 1 ) ); + } + ); + } + + @Entity(name = "A") + public static class A { + @Id + private Integer id; + + private B b; + + } + + @Embeddable + public static class B { + private String value; + + @OneToMany(cascade = CascadeType.ALL) + private List cs; + + public static B buildB() { + B b = new B(); + b.value = "v"; + C c = new C(); + + c.id = 2L; + c.name = "c"; + + List cs = new ArrayList(); + cs.add( c ); + b.cs = cs; + + return b; + } + } + + @Entity(name = "C") + public static class C { + @Id + private Long id; + + private String name; + } + + +}