HHH-16040 New coercing assembler when types are different from expected

This commit is contained in:
Marco Belladelli 2023-01-25 18:26:52 +01:00 committed by Christian Beikov
parent b2689fa929
commit 890e4ad62c
17 changed files with 375 additions and 66 deletions

View File

@ -360,6 +360,7 @@ public class BasicAttributeMapping
// Lazy property. A valuesArrayPosition of -1 will lead to // Lazy property. A valuesArrayPosition of -1 will lead to
// returning a domain result assembler that returns LazyPropertyInitializer.UNFETCHED_PROPERTY // returning a domain result assembler that returns LazyPropertyInitializer.UNFETCHED_PROPERTY
final EntityMappingType containingEntityMapping = findContainingEntityMapping(); final EntityMappingType containingEntityMapping = findContainingEntityMapping();
boolean coerceResultType = false;
if ( fetchTiming == FetchTiming.DELAYED if ( fetchTiming == FetchTiming.DELAYED
&& !( fetchParent instanceof EmbeddableResultGraphNode ) && !( fetchParent instanceof EmbeddableResultGraphNode )
&& containingEntityMapping.getEntityPersister().getPropertyLaziness()[getStateArrayPosition()] ) { && containingEntityMapping.getEntityPersister().getPropertyLaziness()[getStateArrayPosition()] ) {
@ -375,6 +376,10 @@ public class BasicAttributeMapping
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, true, fetchParent, creationState ); final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, true, fetchParent, creationState );
valuesArrayPosition = sqlSelection.getValuesArrayPosition(); valuesArrayPosition = sqlSelection.getValuesArrayPosition();
if ( sqlSelection.getExpressionType() != null) {
// if the expression type is different that the expected type coerce the value
coerceResultType = sqlSelection.getExpressionType().getSingleJdbcMapping().getJdbcJavaType() != getJdbcMapping().getJdbcJavaType();
}
} }
return new BasicFetch<>( return new BasicFetch<>(
@ -383,7 +388,8 @@ public class BasicAttributeMapping
fetchablePath, fetchablePath,
this, this,
fetchTiming, fetchTiming,
creationState creationState,
coerceResultType
); );
} }

View File

@ -22,6 +22,7 @@ import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.NavigableRole;
@ -399,13 +400,16 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
assert tableGroup != null; assert tableGroup != null;
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, false, fetchParent, creationState ); final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, false, fetchParent, creationState );
final JdbcMappingContainer selectionType = sqlSelection.getExpressionType();
return new BasicFetch<>( return new BasicFetch<>(
sqlSelection.getValuesArrayPosition(), sqlSelection.getValuesArrayPosition(),
fetchParent, fetchParent,
fetchablePath, fetchablePath,
this, this,
FetchTiming.IMMEDIATE, FetchTiming.IMMEDIATE,
creationState creationState,
// if the expression type is different that the expected type coerce the value
selectionType != null && selectionType.getSingleJdbcMapping().getJdbcJavaType() != getJdbcMapping().getJdbcJavaType()
); );
} }

View File

@ -22,6 +22,7 @@ import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.ManagedMappingType; import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
@ -316,17 +317,21 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
); );
} }
final JavaType<?> javaType = selectableMapping.getJdbcMapping().getJdbcJavaType();
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection( final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
sqlExpressionResolver.resolveSqlExpression( tableReference, selectableMapping ), sqlExpressionResolver.resolveSqlExpression( tableReference, selectableMapping ),
selectableMapping.getJdbcMapping().getJdbcJavaType(), javaType,
fetchParent, fetchParent,
sqlAstCreationState.getCreationContext().getSessionFactory().getTypeConfiguration() sqlAstCreationState.getCreationContext().getSessionFactory().getTypeConfiguration()
); );
final JdbcMappingContainer selectionType = sqlSelection.getExpressionType();
return new BasicResult<>( return new BasicResult<>(
sqlSelection.getValuesArrayPosition(), sqlSelection.getValuesArrayPosition(),
null, null,
selectableMapping.getJdbcMapping() selectableMapping.getJdbcMapping(),
// if the expression type is different that the expected type coerce the value
selectionType != null && selectionType.getSingleJdbcMapping().getJdbcJavaType() != javaType
); );
} }

View File

@ -55,6 +55,28 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
); );
} }
public BasicFetch(
int valuesArrayPosition,
FetchParent fetchParent,
NavigablePath fetchablePath,
BasicValuedModelPart valuedMapping,
FetchTiming fetchTiming,
DomainResultCreationState creationState,
boolean coerceResultType) {
//noinspection unchecked
this(
valuesArrayPosition,
fetchParent,
fetchablePath,
valuedMapping,
(BasicValueConverter<T, ?>) valuedMapping.getJdbcMapping().getValueConverter(),
fetchTiming,
true,
creationState,
coerceResultType
);
}
public BasicFetch( public BasicFetch(
int valuesArrayPosition, int valuesArrayPosition,
FetchParent fetchParent, FetchParent fetchParent,
@ -84,6 +106,29 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
FetchTiming fetchTiming, FetchTiming fetchTiming,
boolean canBasicPartFetchBeDelayed, boolean canBasicPartFetchBeDelayed,
DomainResultCreationState creationState) { DomainResultCreationState creationState) {
this(
valuesArrayPosition,
fetchParent,
fetchablePath,
valuedMapping,
valueConverter,
fetchTiming,
canBasicPartFetchBeDelayed,
creationState,
false
);
}
public BasicFetch(
int valuesArrayPosition,
FetchParent fetchParent,
NavigablePath fetchablePath,
BasicValuedModelPart valuedMapping,
BasicValueConverter<T, ?> valueConverter,
FetchTiming fetchTiming,
boolean canBasicPartFetchBeDelayed,
DomainResultCreationState creationState,
boolean coerceResultType) {
this.navigablePath = fetchablePath; this.navigablePath = fetchablePath;
this.fetchParent = fetchParent; this.fetchParent = fetchParent;
@ -100,11 +145,12 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
} }
} }
else { else {
this.assembler = new BasicResultAssembler<>( if (coerceResultType) {
valuesArrayPosition, this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
javaType, }
valueConverter else {
); this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
}
} }
} }

View File

@ -41,6 +41,22 @@ public class BasicResult<T> implements DomainResult<T>, BasicResultGraphNode<T>
); );
} }
public BasicResult(
int jdbcValuesArrayPosition,
String resultVariable,
JdbcMapping jdbcMapping,
boolean coerceResultType) {
//noinspection unchecked
this(
jdbcValuesArrayPosition,
resultVariable,
jdbcMapping.getJavaTypeDescriptor(),
jdbcMapping.getValueConverter(),
null,
coerceResultType
);
}
public BasicResult( public BasicResult(
int jdbcValuesArrayPosition, int jdbcValuesArrayPosition,
String resultVariable, String resultVariable,
@ -85,11 +101,26 @@ public class BasicResult<T> implements DomainResult<T>, BasicResultGraphNode<T>
JavaType<T> javaType, JavaType<T> javaType,
BasicValueConverter<T,?> valueConverter, BasicValueConverter<T,?> valueConverter,
NavigablePath navigablePath) { NavigablePath navigablePath) {
this( valuesArrayPosition, resultVariable, javaType, valueConverter, navigablePath, false );
}
public BasicResult(
int valuesArrayPosition,
String resultVariable,
JavaType<T> javaType,
BasicValueConverter<T,?> valueConverter,
NavigablePath navigablePath,
boolean coerceResultType) {
this.resultVariable = resultVariable; this.resultVariable = resultVariable;
this.javaType = javaType; this.javaType = javaType;
this.navigablePath = navigablePath; this.navigablePath = navigablePath;
this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter ); if ( coerceResultType ) {
this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
}
else {
this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter );
}
} }
@Override @Override

View File

@ -26,8 +26,8 @@ public class BasicResultAssembler<J> implements DomainResultAssembler<J> {
return new BasicResultAssembler<>( selection.getValuesArrayPosition(), javaType ); return new BasicResultAssembler<>( selection.getValuesArrayPosition(), javaType );
} }
private final int valuesArrayPosition; protected final int valuesArrayPosition;
private final JavaType<J> assembledJavaType; protected final JavaType<J> assembledJavaType;
private final BasicValueConverter<J,?> valueConverter; private final BasicValueConverter<J,?> valueConverter;
public BasicResultAssembler( public BasicResultAssembler(

View File

@ -0,0 +1,38 @@
/*
* 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.sql.results.graph.basic;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;
/**
* A {@link BasicResultAssembler} which does type coercion to handle cases
* where the expression type and the expected result {@link JavaType} are different
* (e.g. same column mapped with differently typed properties).
*
* @author Marco Belladelli
*/
public class CoercingResultAssembler<J> extends BasicResultAssembler<J> {
public CoercingResultAssembler(
int valuesArrayPosition,
JavaType<J> assembledJavaType,
BasicValueConverter<J, ?> valueConverter) {
super( valuesArrayPosition, assembledJavaType, valueConverter );
}
/**
* Access to the row value, coerced to expected type
*/
@Override
public Object extractRawValue(RowProcessingState rowProcessingState) {
return assembledJavaType.coerce(
rowProcessingState.getJdbcValue( valuesArrayPosition ),
rowProcessingState.getSession()
);
}
}

View File

@ -92,4 +92,9 @@ public class PrimitiveCharacterArrayJavaType extends AbstractClassJavaType<char[
} }
throw unknownWrap( value.getClass() ); throw unknownWrap( value.getClass() );
} }
@Override
public <X> char[] coerce(X value, CoercionContext coercionContext) {
return wrap( value, null );
}
} }

View File

@ -90,6 +90,9 @@ public class StringJavaType extends AbstractClassJavaType<String> {
if (value instanceof String) { if (value instanceof String) {
return (String) value; return (String) value;
} }
if (value instanceof char[]) {
return new String( (char[]) value );
}
if (value instanceof Reader) { if (value instanceof Reader) {
return DataHelper.extractString( (Reader) value ); return DataHelper.extractString( (Reader) value );
} }
@ -113,4 +116,8 @@ public class StringJavaType extends AbstractClassJavaType<String> {
} }
} }
@Override
public <X> String coerce(X value, CoercionContext coercionContext) {
return wrap( value, null );
}
} }

View File

@ -42,6 +42,7 @@ import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.Root;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
/** /**
* @author Marco Belladelli * @author Marco Belladelli
@ -65,7 +66,7 @@ public class TreatPathTest {
term.setLength( 4 ); term.setLength( 4 );
term.setLanguage( language ); term.setLanguage( language );
term.setAnyProperty( stringProperty ); term.setAnyProperty( stringProperty );
term.setSynonyms( new ArrayList<>( List.of( "ciao" ) ) ); term.setSynonyms( new ArrayList<>() );
term.setEmbeddableProperty( new EmbeddableType( "ciao" ) ); term.setEmbeddableProperty( new EmbeddableType( "ciao" ) );
Linkage linkage = new Linkage(); Linkage linkage = new Linkage();
linkage.setTerm( term ); linkage.setTerm( term );
@ -101,14 +102,7 @@ public class TreatPathTest {
@Test @Test
public void testTreatPluralValue(EntityManagerFactoryScope scope) { public void testTreatPluralValue(EntityManagerFactoryScope scope) {
scope.inTransaction( entityManager -> { scope.inTransaction( entityManager -> testCriteriaTreat( entityManager, "synonyms", null, true ) );
try {
testCriteriaTreat( entityManager, "synonyms", List.of( "ciao" ) );
}
catch (Exception e) {
assertEquals( UnsupportedOperationException.class, e.getClass() );
}
} );
} }
@Test @Test
@ -129,13 +123,17 @@ public class TreatPathTest {
} }
private void testCriteriaTreat(EntityManager entityManager, String property, Object value) { private void testCriteriaTreat(EntityManager entityManager, String property, Object value) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); testCriteriaTreat( entityManager, property, value, false );
CriteriaQuery<Linkage> criteria = cb.createQuery( Linkage.class ); }
Root<Linkage> root = criteria.from( Linkage.class );
Path<LocalTerm> asLocalTerm = cb.treat( root.get( "term" ), LocalTerm.class ); private void testCriteriaTreat(EntityManager entityManager, String property, Object value, boolean plural) {
Predicate predicate; final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
if ( value instanceof Collection<?> ) { final CriteriaQuery<Linkage> criteria = cb.createQuery( Linkage.class );
predicate = asLocalTerm.get( property ).in( value ); final Root<Linkage> root = criteria.from( Linkage.class );
final Path<LocalTerm> asLocalTerm = cb.treat( root.get( "term" ), LocalTerm.class );
final Predicate predicate;
if ( plural ) {
predicate = cb.isEmpty( asLocalTerm.get( property ) );
} }
else { else {
predicate = cb.equal( asLocalTerm.get( property ), value ); predicate = cb.equal( asLocalTerm.get( property ), value );

View File

@ -7,6 +7,7 @@
package org.hibernate.orm.test.mapping.joincolumn; package org.hibernate.orm.test.mapping.joincolumn;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
@ -23,6 +24,7 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -43,10 +45,10 @@ public class CharArrayToStringJoinColumnTest {
vehicle.setId( 1L ); vehicle.setId( 1L );
vehicle.setStringProp( "2020" ); vehicle.setStringProp( "2020" );
session.persist( vehicle ); session.persist( vehicle );
VehicleInvoice invoice = new VehicleInvoice(); VehicleInvoice invoice = new VehicleInvoice();
invoice.setId( "2020".toCharArray() ); invoice.setId( "2020".toCharArray() );
invoice.setVehicle( vehicle ); invoice.setVehicle( vehicle );
vehicle.getInvoices().add( invoice );
session.persist( invoice ); session.persist( invoice );
} ); } );
} }
@ -62,13 +64,24 @@ public class CharArrayToStringJoinColumnTest {
@Test @Test
public void testAssociation(SessionFactoryScope scope) { public void testAssociation(SessionFactoryScope scope) {
scope.inTransaction( session -> { scope.inTransaction( session -> {
List<VehicleInvoice> resultList = session.createQuery( final VehicleInvoice vehicleInvoice = session.createQuery(
"from VehicleInvoice", "from VehicleInvoice",
VehicleInvoice.class VehicleInvoice.class
).getResultList(); ).getSingleResult();
assertEquals( 1, resultList.size() ); assertEquals( 1L, vehicleInvoice.getVehicle().getId() );
assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); assertEquals( "2020", vehicleInvoice.getVehicle().getStringProp() );
assertEquals( "2020", resultList.get( 0 ).getVehicle().getStringProp() ); } );
}
@Test
public void testInverse(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final Vehicle vehicle = session.createQuery(
"from Vehicle",
Vehicle.class
).getSingleResult();
assertEquals( 1, vehicle.getInvoices().size() );
assertEquals( "2020", new String( vehicle.getInvoices().get( 0 ).getId() ) );
} ); } );
} }
@ -107,6 +120,13 @@ public class CharArrayToStringJoinColumnTest {
@Column(name = "string_col", nullable = false) @Column(name = "string_col", nullable = false)
private String stringProp; private String stringProp;
@OneToMany(mappedBy = "vehicle")
private List<VehicleInvoice> invoices;
public Vehicle() {
this.invoices = new ArrayList<>();
}
public Long getId() { public Long getId() {
return id; return id;
} }
@ -122,6 +142,14 @@ public class CharArrayToStringJoinColumnTest {
public void setStringProp(String stringProp) { public void setStringProp(String stringProp) {
this.stringProp = stringProp; this.stringProp = stringProp;
} }
public List<VehicleInvoice> getInvoices() {
return invoices;
}
public void setInvoices(List<VehicleInvoice> invoices) {
this.invoices = invoices;
}
} }
} }

View File

@ -7,6 +7,7 @@
package org.hibernate.orm.test.mapping.joincolumn; package org.hibernate.orm.test.mapping.joincolumn;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
@ -23,6 +24,7 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -43,10 +45,10 @@ public class StringToCharArrayJoinColumnTest {
vehicle.setId( 1L ); vehicle.setId( 1L );
vehicle.setCharArrayProp( "2020".toCharArray() ); vehicle.setCharArrayProp( "2020".toCharArray() );
session.persist( vehicle ); session.persist( vehicle );
VehicleInvoice invoice = new VehicleInvoice(); VehicleInvoice invoice = new VehicleInvoice();
invoice.setId( "2020" ); invoice.setId( "2020" );
invoice.setVehicle( vehicle ); invoice.setVehicle( vehicle );
vehicle.getInvoices().add( invoice );
session.persist( invoice ); session.persist( invoice );
} ); } );
} }
@ -62,16 +64,28 @@ public class StringToCharArrayJoinColumnTest {
@Test @Test
public void testAssociation(SessionFactoryScope scope) { public void testAssociation(SessionFactoryScope scope) {
scope.inTransaction( session -> { scope.inTransaction( session -> {
List<VehicleInvoice> resultList = session.createQuery( final VehicleInvoice vehicleInvoice = session.createQuery(
"from VehicleInvoice", "from VehicleInvoice",
VehicleInvoice.class VehicleInvoice.class
).getResultList(); ).getSingleResult();
assertEquals( 1, resultList.size() ); assertEquals( 1L, vehicleInvoice.getVehicle().getId() );
assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); assertEquals( "2020", new String( vehicleInvoice.getVehicle().getCharArrayProp() ) );
assertEquals( "2020", new String( resultList.get( 0 ).getVehicle().getCharArrayProp() ));
} ); } );
} }
@Test
public void testInverse(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final Vehicle vehicle = session.createQuery(
"from Vehicle",
Vehicle.class
).getSingleResult();
assertEquals( 1, vehicle.getInvoices().size() );
assertEquals( "2020", vehicle.getInvoices().get( 0 ).getId() );
} );
}
@Entity(name = "VehicleInvoice") @Entity(name = "VehicleInvoice")
public static class VehicleInvoice { public static class VehicleInvoice {
@Id @Id
@ -107,6 +121,13 @@ public class StringToCharArrayJoinColumnTest {
@Column(name = "char_array_col", nullable = false) @Column(name = "char_array_col", nullable = false)
private char[] charArrayProp; private char[] charArrayProp;
@OneToMany(mappedBy = "vehicle")
private List<VehicleInvoice> invoices;
public Vehicle() {
this.invoices = new ArrayList<>();
}
public Long getId() { public Long getId() {
return id; return id;
} }
@ -122,6 +143,14 @@ public class StringToCharArrayJoinColumnTest {
public void setCharArrayProp(char[] charArrayProp) { public void setCharArrayProp(char[] charArrayProp) {
this.charArrayProp = charArrayProp; this.charArrayProp = charArrayProp;
} }
public List<VehicleInvoice> getInvoices() {
return invoices;
}
public void setInvoices(List<VehicleInvoice> invoices) {
this.invoices = invoices;
}
} }
} }

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later * 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 * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/ */
package org.hibernate.orm.test.mapping.joincolumn; package org.hibernate.orm.test.mapping.joincolumn.embedded;
import java.io.Serializable; import java.io.Serializable;
@ -101,7 +101,7 @@ public class CharArrayToStringInEmbeddedJoinColumnOrFormulaTest {
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumnsOrFormulas({ @JoinColumnsOrFormulas({
@JoinColumnOrFormula(formula = @JoinFormula(value = "trim(char_array_col_1)", referencedColumnName = "string_col_1")), @JoinColumnOrFormula(formula = @JoinFormula(value = "char_array_col_1", referencedColumnName = "string_col_1")),
@JoinColumnOrFormula(column = @JoinColumn(name = "char_array_col_2", referencedColumnName = "string_col_2", insertable = false, updatable = false)) @JoinColumnOrFormula(column = @JoinColumn(name = "char_array_col_2", referencedColumnName = "string_col_2", insertable = false, updatable = false))
}) })
private Vehicle vehicle; private Vehicle vehicle;

View File

@ -7,6 +7,7 @@
package org.hibernate.orm.test.mapping.joincolumn.embedded; package org.hibernate.orm.test.mapping.joincolumn.embedded;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
@ -25,6 +26,7 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -45,10 +47,10 @@ public class CharArrayToStringInEmbeddedJoinColumnTest {
vehicle.setId( 1L ); vehicle.setId( 1L );
vehicle.setStringProp( "2020" ); vehicle.setStringProp( "2020" );
session.persist( vehicle ); session.persist( vehicle );
VehicleInvoice invoice = new VehicleInvoice(); VehicleInvoice invoice = new VehicleInvoice();
invoice.setId( new VehicleInvoiceId( "2020".toCharArray(), 2020 ) ); invoice.setId( new VehicleInvoiceId( "2020".toCharArray(), 2020 ) );
invoice.setVehicle( vehicle ); invoice.setVehicle( vehicle );
vehicle.getInvoices().add( invoice );
session.persist( invoice ); session.persist( invoice );
} ); } );
} }
@ -64,13 +66,24 @@ public class CharArrayToStringInEmbeddedJoinColumnTest {
@Test @Test
public void testAssociation(SessionFactoryScope scope) { public void testAssociation(SessionFactoryScope scope) {
scope.inTransaction( session -> { scope.inTransaction( session -> {
List<VehicleInvoice> resultList = session.createQuery( final VehicleInvoice vehicleInvoice = session.createQuery(
"from VehicleInvoice", "from VehicleInvoice",
VehicleInvoice.class VehicleInvoice.class
).getResultList(); ).getSingleResult();
assertEquals( 1, resultList.size() ); assertEquals( 1L, vehicleInvoice.getVehicle().getId() );
assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); assertEquals( "2020", vehicleInvoice.getVehicle().getStringProp() );
assertEquals( "2020", resultList.get( 0 ).getVehicle().getStringProp() ); } );
}
@Test
public void testInverse(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final Vehicle vehicle = session.createQuery(
"from Vehicle",
Vehicle.class
).getSingleResult();
assertEquals( 1, vehicle.getInvoices().size() );
assertEquals( "2020", new String( vehicle.getInvoices().get( 0 ).getId().getCharArrayProp() ) );
} ); } );
} }
@ -141,6 +154,13 @@ public class CharArrayToStringInEmbeddedJoinColumnTest {
@Column(name = "string_col", nullable = false) @Column(name = "string_col", nullable = false)
private String stringProp; private String stringProp;
@OneToMany(mappedBy = "vehicle")
private List<VehicleInvoice> invoices;
public Vehicle() {
this.invoices = new ArrayList<>();
}
public Long getId() { public Long getId() {
return id; return id;
} }
@ -156,6 +176,14 @@ public class CharArrayToStringInEmbeddedJoinColumnTest {
public void setStringProp(String stringProp) { public void setStringProp(String stringProp) {
this.stringProp = stringProp; this.stringProp = stringProp;
} }
public List<VehicleInvoice> getInvoices() {
return invoices;
}
public void setInvoices(List<VehicleInvoice> invoices) {
this.invoices = invoices;
}
} }
} }

View File

@ -7,6 +7,7 @@
package org.hibernate.orm.test.mapping.joincolumn.embedded; package org.hibernate.orm.test.mapping.joincolumn.embedded;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
@ -25,6 +26,7 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -46,10 +48,10 @@ public class CharArrayToStringInEmbeddedMultipleJoinColumnTest {
vehicle.setStringProp( "2020" ); vehicle.setStringProp( "2020" );
vehicle.setIntProp( 2020 ); vehicle.setIntProp( 2020 );
session.persist( vehicle ); session.persist( vehicle );
VehicleInvoice invoice = new VehicleInvoice(); VehicleInvoice invoice = new VehicleInvoice();
invoice.setId( new VehicleInvoiceId( "2020".toCharArray(), 2020 ) ); invoice.setId( new VehicleInvoiceId( "2020".toCharArray(), 2020 ) );
invoice.setVehicle( vehicle ); invoice.setVehicle( vehicle );
vehicle.getInvoices().add( invoice );
session.persist( invoice ); session.persist( invoice );
} ); } );
} }
@ -65,13 +67,24 @@ public class CharArrayToStringInEmbeddedMultipleJoinColumnTest {
@Test @Test
public void testAssociation(SessionFactoryScope scope) { public void testAssociation(SessionFactoryScope scope) {
scope.inTransaction( session -> { scope.inTransaction( session -> {
List<VehicleInvoice> resultList = session.createQuery( final VehicleInvoice vehicleInvoice = session.createQuery(
"from VehicleInvoice", "from VehicleInvoice",
VehicleInvoice.class VehicleInvoice.class
).getResultList(); ).getSingleResult();
assertEquals( 1, resultList.size() ); assertEquals( 1L, vehicleInvoice.getVehicle().getId() );
assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); assertEquals( "2020", vehicleInvoice.getVehicle().getStringProp() );
assertEquals( "2020", resultList.get( 0 ).getVehicle().getStringProp() ); } );
}
@Test
public void testInverse(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final Vehicle vehicle = session.createQuery(
"from Vehicle",
Vehicle.class
).getSingleResult();
assertEquals( 1, vehicle.getInvoices().size() );
assertEquals( "2020", new String( vehicle.getInvoices().get( 0 ).getId().getCharArrayProp() ) );
} ); } );
} }
@ -146,6 +159,13 @@ public class CharArrayToStringInEmbeddedMultipleJoinColumnTest {
@Column(name = "int_col", nullable = false) @Column(name = "int_col", nullable = false)
private int intProp; private int intProp;
@OneToMany(mappedBy = "vehicle")
private List<VehicleInvoice> invoices;
public Vehicle() {
this.invoices = new ArrayList<>();
}
public Long getId() { public Long getId() {
return id; return id;
} }
@ -169,6 +189,14 @@ public class CharArrayToStringInEmbeddedMultipleJoinColumnTest {
public void setIntProp(int intProp) { public void setIntProp(int intProp) {
this.intProp = intProp; this.intProp = intProp;
} }
public List<VehicleInvoice> getInvoices() {
return invoices;
}
public void setInvoices(List<VehicleInvoice> invoices) {
this.invoices = invoices;
}
} }
} }

View File

@ -7,6 +7,7 @@
package org.hibernate.orm.test.mapping.joincolumn.embedded; package org.hibernate.orm.test.mapping.joincolumn.embedded;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
@ -25,6 +26,7 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -45,10 +47,10 @@ public class StringToCharArrayInEmbeddedJoinColumnTest {
vehicle.setId( 1L ); vehicle.setId( 1L );
vehicle.setCharArrayProp( "2020".toCharArray() ); vehicle.setCharArrayProp( "2020".toCharArray() );
session.persist( vehicle ); session.persist( vehicle );
VehicleInvoice invoice = new VehicleInvoice(); VehicleInvoice invoice = new VehicleInvoice();
invoice.setId( new VehicleInvoiceId( "2020", 2020 ) ); invoice.setId( new VehicleInvoiceId( "2020", 2020 ) );
invoice.setVehicle( vehicle ); invoice.setVehicle( vehicle );
vehicle.getInvoices().add( invoice );
session.persist( invoice ); session.persist( invoice );
} ); } );
} }
@ -64,13 +66,24 @@ public class StringToCharArrayInEmbeddedJoinColumnTest {
@Test @Test
public void testAssociation(SessionFactoryScope scope) { public void testAssociation(SessionFactoryScope scope) {
scope.inTransaction( session -> { scope.inTransaction( session -> {
List<VehicleInvoice> resultList = session.createQuery( final VehicleInvoice vehicleInvoice = session.createQuery(
"from VehicleInvoice", "from VehicleInvoice",
VehicleInvoice.class VehicleInvoice.class
).getResultList(); ).getSingleResult();
assertEquals( 1, resultList.size() ); assertEquals( 1L, vehicleInvoice.getVehicle().getId() );
assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); assertEquals( "2020", new String( vehicleInvoice.getVehicle().getCharArrayProp() ) );
assertEquals( "2020", new String( resultList.get( 0 ).getVehicle().getCharArrayProp() ) ); } );
}
@Test
public void testInverse(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final Vehicle vehicle = session.createQuery(
"from Vehicle",
Vehicle.class
).getSingleResult();
assertEquals( 1, vehicle.getInvoices().size() );
assertEquals( "2020", vehicle.getInvoices().get( 0 ).getId().getStringProp() );
} ); } );
} }
@ -141,6 +154,13 @@ public class StringToCharArrayInEmbeddedJoinColumnTest {
@Column(name = "char_array_col", nullable = false) @Column(name = "char_array_col", nullable = false)
private char[] charArrayProp; private char[] charArrayProp;
@OneToMany(mappedBy = "vehicle")
private List<VehicleInvoice> invoices;
public Vehicle() {
this.invoices = new ArrayList<>();
}
public Long getId() { public Long getId() {
return id; return id;
} }
@ -156,6 +176,14 @@ public class StringToCharArrayInEmbeddedJoinColumnTest {
public void setCharArrayProp(char[] charArrayProp) { public void setCharArrayProp(char[] charArrayProp) {
this.charArrayProp = charArrayProp; this.charArrayProp = charArrayProp;
} }
public List<VehicleInvoice> getInvoices() {
return invoices;
}
public void setInvoices(List<VehicleInvoice> invoices) {
this.invoices = invoices;
}
} }
} }

View File

@ -7,6 +7,7 @@
package org.hibernate.orm.test.mapping.joincolumn.embedded; package org.hibernate.orm.test.mapping.joincolumn.embedded;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
@ -25,6 +26,7 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -46,10 +48,10 @@ public class StringToCharArrayInEmbeddedMultipleJoinColumnTest {
vehicle.setCharArrayProp( "2020".toCharArray() ); vehicle.setCharArrayProp( "2020".toCharArray() );
vehicle.setIntProp( 2020 ); vehicle.setIntProp( 2020 );
session.persist( vehicle ); session.persist( vehicle );
VehicleInvoice invoice = new VehicleInvoice(); VehicleInvoice invoice = new VehicleInvoice();
invoice.setId( new VehicleInvoiceId( "2020", 2020 ) ); invoice.setId( new VehicleInvoiceId( "2020", 2020 ) );
invoice.setVehicle( vehicle ); invoice.setVehicle( vehicle );
vehicle.getInvoices().add( invoice );
session.persist( invoice ); session.persist( invoice );
} ); } );
} }
@ -65,13 +67,24 @@ public class StringToCharArrayInEmbeddedMultipleJoinColumnTest {
@Test @Test
public void testAssociation(SessionFactoryScope scope) { public void testAssociation(SessionFactoryScope scope) {
scope.inTransaction( session -> { scope.inTransaction( session -> {
List<VehicleInvoice> resultList = session.createQuery( final VehicleInvoice vehicleInvoice = session.createQuery(
"from VehicleInvoice", "from VehicleInvoice",
VehicleInvoice.class VehicleInvoice.class
).getResultList(); ).getSingleResult();
assertEquals( 1, resultList.size() ); assertEquals( 1L, vehicleInvoice.getVehicle().getId() );
assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); assertEquals( "2020", new String( vehicleInvoice.getVehicle().getCharArrayProp() ) );
assertEquals( "2020", new String( resultList.get( 0 ).getVehicle().getCharArrayProp() )); } );
}
@Test
public void testInverse(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final Vehicle vehicle = session.createQuery(
"from Vehicle",
Vehicle.class
).getSingleResult();
assertEquals( 1, vehicle.getInvoices().size() );
assertEquals( "2020", vehicle.getInvoices().get( 0 ).getId().getStringProp() );
} ); } );
} }
@ -146,6 +159,13 @@ public class StringToCharArrayInEmbeddedMultipleJoinColumnTest {
@Column(name = "int_col", nullable = false) @Column(name = "int_col", nullable = false)
private int intProp; private int intProp;
@OneToMany(mappedBy = "vehicle")
private List<VehicleInvoice> invoices;
public Vehicle() {
this.invoices = new ArrayList<>();
}
public Long getId() { public Long getId() {
return id; return id;
} }
@ -169,6 +189,14 @@ public class StringToCharArrayInEmbeddedMultipleJoinColumnTest {
public void setIntProp(int intProp) { public void setIntProp(int intProp) {
this.intProp = intProp; this.intProp = intProp;
} }
public List<VehicleInvoice> getInvoices() {
return invoices;
}
public void setInvoices(List<VehicleInvoice> invoices) {
this.invoices = invoices;
}
} }
} }