Embedded collection member of and Embeddable parameter binding

This commit is contained in:
Andrea Boriero 2020-08-07 08:22:03 +01:00
parent 7e87deb349
commit 38753afab6
17 changed files with 488 additions and 51 deletions

View File

@ -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(),

View File

@ -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 ) {

View File

@ -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()

View File

@ -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,

View File

@ -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,

View File

@ -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 <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
return new EmbeddableResultImpl<>(
navigablePath,
this,
resultVariable,
creationState
);
}
@Override
public Nature getNature() {
return nature;

View File

@ -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<J>
private final ManagedDomainType<? super J> superType;
private final RepresentationMode representationMode;
private final Map<String, SingularPersistentAttribute<J, ?>> declaredSingularAttributes = new HashMap<>();
private final Map<String, PluralPersistentAttribute<J, ?, ?>> declaredPluralAttributes = new HashMap<>();
private final Map<String, SingularPersistentAttribute<J, ?>> declaredSingularAttributes = new LinkedHashMap<>();
private final Map<String, PluralPersistentAttribute<J, ?, ?>> declaredPluralAttributes = new LinkedHashMap<>();
private final List<ManagedDomainType> subTypes = new ArrayList<>();
@ -104,7 +106,7 @@ public abstract class AbstractManagedType<J>
@Override
@SuppressWarnings("unchecked")
public Set<Attribute<? super J, ?>> 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<J>
return Collections.emptySet();
}
final HashSet attributes = new HashSet<>( declaredSingularAttributes.values() );
final HashSet attributes = new LinkedHashSet( declaredSingularAttributes.values() );
attributes.addAll( declaredPluralAttributes.values() );
return attributes;
}

View File

@ -18,6 +18,6 @@ import org.hibernate.metamodel.spi.ManagedTypeRepresentationStrategy;
*
* @author Steve Ebersole
*/
public interface EmbeddableDomainType<J> extends ManagedDomainType<J>, EmbeddableType<J> {
public interface EmbeddableDomainType<J> extends ManagedDomainType<J>, EmbeddableType<J>, AllowableParameterType<J> {
ManagedTypeRepresentationStrategy getRepresentationStrategy();
}

View File

@ -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<J>
extends AbstractManagedType<J>
implements EmbeddableDomainType<J>, Serializable {
implements EmbeddableDomainType<J>, Serializable, MappingModelExpressable<J> {
private final ManagedTypeRepresentationStrategy representationStrategy;
private final EmbeddableRepresentationStrategy representationStrategy;
public EmbeddableTypeImpl(
JavaTypeDescriptor<J> javaTypeDescriptor,
ManagedTypeRepresentationStrategy representationStrategy,
EmbeddableRepresentationStrategy representationStrategy,
JpaMetamodel domainMetamodel) {
super( javaTypeDescriptor.getJavaType().getName(), javaTypeDescriptor, null, domainMetamodel );
this.representationStrategy = representationStrategy;
@ -71,4 +86,75 @@ public class EmbeddableTypeImpl<J>
public <S extends J> SubGraphImplementor<S> makeSubGraph(Class<S> 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<JdbcMapping> 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<JdbcMapping> action,
Clause clause,
TypeConfiguration typeConfiguration) {
Set<Attribute<? super J, ?>> 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<Attribute<? super J, ?>> attributes = getAttributes();
final List<Object> 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();
}
}

View File

@ -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 );
}

View File

@ -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();

View File

@ -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<Address> 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<Address> getAddresses() {
return addresses;
}
public void setAddresses(Set<Address> 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;
}
}
}

View File

@ -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 -> {

View File

@ -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();

View File

@ -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 ) );
}
);
}

View File

@ -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<EntityTest> 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;
}
}

View File

@ -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<C> 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;
}
}