Skip to content

Commit

Permalink
HHH-18730 Multi-column association in aggregate component doesn't work
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed Oct 18, 2024
1 parent d647599 commit 9bb5e64
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.sql.NClob;
import java.sql.SQLException;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.Internal;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
Expand Down Expand Up @@ -127,13 +128,13 @@ public static Object[] getJdbcValues(

private static int injectJdbcValues(
EmbeddableMappingType embeddableMappingType,
Object domainValue,
@Nullable Object domainValue,
Object[] jdbcValues,
int jdbcIndex,
WrapperOptions options) throws SQLException {
return injectJdbcValues(
embeddableMappingType,
embeddableMappingType.getValues( domainValue ),
domainValue == null ? null : embeddableMappingType.getValues( domainValue ),
jdbcValues,
jdbcIndex,
options
Expand All @@ -142,12 +143,15 @@ private static int injectJdbcValues(

private static int injectJdbcValues(
EmbeddableMappingType embeddableMappingType,
Object[] values,
@Nullable Object[] values,
Object[] jdbcValues,
int jdbcIndex,
WrapperOptions options) throws SQLException {
final int jdbcValueCount = embeddableMappingType.getJdbcValueCount();
final int valueCount = jdbcValueCount + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
if ( values == null ) {
return valueCount;
}
int offset = 0;
for ( int i = 0; i < values.length; i++ ) {
offset += injectJdbcValue(
Expand Down Expand Up @@ -252,22 +256,13 @@ else if ( attributeMapping instanceof EmbeddableValuedModelPart ) {
);
}
else {
jdbcValueCount = embeddableMappingType.getJdbcValueCount() + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
final int numberOfValues = numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
final Object[] subValues = embeddableMappingType.getValues( attributeValues[attributeIndex] );
int offset = 0;
for ( int i = 0; i < numberOfValues; i++ ) {
offset += injectJdbcValue(
getEmbeddedPart( embeddableMappingType, i ),
subValues,
i,
jdbcValues,
jdbcIndex + offset,
options
);
}
assert offset == jdbcValueCount;
jdbcValueCount = injectJdbcValues(
embeddableMappingType,
attributeValues[attributeIndex],
jdbcValues,
jdbcIndex,
options
);
}
}
else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.component;

import jakarta.persistence.Embeddable;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Struct;
import org.hibernate.testing.jdbc.SharedDriverManagerTypeCacheClearingIntegrator;
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
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;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

@BootstrapServiceRegistry(
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
integrators = SharedDriverManagerTypeCacheClearingIntegrator.class
)
@DomainModel(
annotatedClasses = {
StructComponentManyToOneCompositeTest.Book.class
}
)
@SessionFactory
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStructAggregate.class)
public class StructComponentManyToOneCompositeTest {

@BeforeEach
public void setUp(SessionFactoryScope scope){
scope.inTransaction(
session -> {
Book book1 = new Book();
book1.id = 1L;
book1.id2 = 1L;
book1.title = "Hibernate 3";
book1.author = new Author( "Gavin", null );

session.persist( book1 );

Book book2 = new Book();
book2.id = 2L;
book2.id2 = 2L;
book2.title = "Hibernate 6";
book2.author = new Author( "Steve", book1 );

session.persist( book2 );
}
);
}

@AfterEach
public void tearDown(SessionFactoryScope scope){
scope.inTransaction(
session ->
session.createQuery( "delete from Book" ).executeUpdate()
);
}

@Test
public void testGet(SessionFactoryScope scope){
scope.inTransaction(
session -> {
Book book = session.createQuery( "from Book b where b.id = 2", Book.class ).getSingleResult();
assertFalse( Hibernate.isInitialized( book.author.getFavoriteBook() ) );
assertEquals( "Gavin", book.author.getFavoriteBook().getAuthor().getName() );
}
);
}

@Test
public void testJoin(SessionFactoryScope scope){
scope.inTransaction(
session -> {
Book book = session.createQuery(
"from Book b join fetch b.author.favoriteBook where b.id = 2",
Book.class
).getSingleResult();
assertTrue( Hibernate.isInitialized( book.author.getFavoriteBook() ) );
assertEquals( "Gavin", book.author.getFavoriteBook().getAuthor().getName() );
}
);
}

@Entity(name = "Book")
public static class Book {
@Id
private Long id;
@Id
private Long id2;
private String title;
private Author author;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Long getId2() {
return id2;
}

public void setId2(Long id2) {
this.id2 = id2;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public Author getAuthor() {
return author;
}

public void setAuthor(Author author) {
this.author = author;
}
}

@Embeddable
@Struct( name = "author_type")
public static class Author {

private String name;
@ManyToOne(fetch = FetchType.LAZY)
private Book favoriteBook;

public Author() {
}

public Author(String name, Book favoriteBook) {
this.name = name;
this.favoriteBook = favoriteBook;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Book getFavoriteBook() {
return favoriteBook;
}

public void setFavoriteBook(Book favoriteBook) {
this.favoriteBook = favoriteBook;
}
}

}

0 comments on commit 9bb5e64

Please sign in to comment.