HHH-15393 - Improve write-paths to use mapping model
This commit is contained in:
parent
26e7393775
commit
631d0bad71
|
@ -9,17 +9,20 @@ package org.hibernate.metamodel.mapping.internal;
|
|||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.IndexedCollection;
|
||||
import org.hibernate.mapping.ManyToOne;
|
||||
import org.hibernate.mapping.Map;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.mapping.Association;
|
||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||
|
@ -32,6 +35,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.VirtualModelPart;
|
||||
import org.hibernate.persister.collection.BasicCollectionPersister;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.mutation.CollectionMutationTarget;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
@ -222,16 +226,17 @@ public class ManyToManyCollectionPart extends AbstractEntityCollectionPart imple
|
|||
null
|
||||
);
|
||||
|
||||
lazyTableGroup.setTableGroupInitializerCallback(
|
||||
tableGroup -> join.applyPredicate(
|
||||
foreignKey.generateJoinPredicate(
|
||||
tableGroup.getPrimaryTableReference(),
|
||||
collectionTableGroup.resolveTableReference( foreignKey.getKeyTable() ),
|
||||
sqlExpressionResolver,
|
||||
creationContext
|
||||
)
|
||||
)
|
||||
);
|
||||
lazyTableGroup.setTableGroupInitializerCallback( (partTableGroup) -> {
|
||||
// `partTableGroup` is the association table group
|
||||
join.applyPredicate(
|
||||
foreignKey.generateJoinPredicate(
|
||||
partTableGroup.getPrimaryTableReference(),
|
||||
collectionTableGroup.resolveTableReference( foreignKey.getKeyTable() ),
|
||||
sqlExpressionResolver,
|
||||
creationContext
|
||||
)
|
||||
);
|
||||
} );
|
||||
|
||||
return join;
|
||||
}
|
||||
|
@ -341,13 +346,38 @@ public class ManyToManyCollectionPart extends AbstractEntityCollectionPart imple
|
|||
}
|
||||
else if ( StringHelper.isNotEmpty( bootCollectionDescriptor.getMappedByProperty() ) ) {
|
||||
final ModelPart mappedByPart = resolveNamedTargetPart( bootCollectionDescriptor.getMappedByProperty(), getAssociatedEntityMappingType(), collectionDescriptor );
|
||||
if ( mappedByPart instanceof Association ) {
|
||||
final Association toOne = (Association) mappedByPart;
|
||||
if ( toOne.getForeignKeyDescriptor() == null ) {
|
||||
// key is not yet ready, we need to wait
|
||||
return false;
|
||||
}
|
||||
foreignKey = toOne.getForeignKeyDescriptor();
|
||||
if ( mappedByPart instanceof ToOneAttributeMapping ) {
|
||||
////////////////////////////////////////////////
|
||||
// E.g.
|
||||
//
|
||||
// @Entity
|
||||
// class Book {
|
||||
// ...
|
||||
// @ManyToOne(fetch = FetchType.LAZY)
|
||||
// @JoinTable(name = "author_book",
|
||||
// joinColumns = @JoinColumn(name = "book_id"),
|
||||
// inverseJoinColumns = @JoinColumn(name="author_id",nullable = false))
|
||||
// private Author author;
|
||||
// }
|
||||
//
|
||||
// @Entity
|
||||
// class Author {
|
||||
// ...
|
||||
// @OneToMany(mappedBy = "author")
|
||||
// private List<Book> books;
|
||||
// }
|
||||
|
||||
// create the foreign-key from the join-table (author_book) to the part table (Book) :
|
||||
// `author_book.book_id -> Book.id`
|
||||
|
||||
final ManyToOne elementDescriptor = (ManyToOne) bootCollectionDescriptor.getElement();
|
||||
assert elementDescriptor.isReferenceToPrimaryKey();
|
||||
|
||||
final String collectionTableName = ( (BasicCollectionPersister) collectionDescriptor ).getTableName();
|
||||
|
||||
foreignKey = createJoinTablePartForeignKey( collectionTableName, elementDescriptor, creationProcess );
|
||||
|
||||
creationProcess.registerForeignKey( this, foreignKey );
|
||||
}
|
||||
else {
|
||||
final PluralAttributeMapping manyToManyInverse = (PluralAttributeMapping) mappedByPart;
|
||||
|
@ -389,6 +419,58 @@ public class ManyToManyCollectionPart extends AbstractEntityCollectionPart imple
|
|||
return true;
|
||||
}
|
||||
|
||||
private ForeignKeyDescriptor createJoinTablePartForeignKey(
|
||||
String collectionTableName,
|
||||
ManyToOne elementDescriptor,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
final EntityIdentifierMapping identifierMapping = getAssociatedEntityMappingType().getIdentifierMapping();
|
||||
if ( identifierMapping.getNature() == EntityIdentifierMapping.Nature.SIMPLE ) {
|
||||
final BasicEntityIdentifierMapping basicIdMapping = (BasicEntityIdentifierMapping) identifierMapping;
|
||||
|
||||
assert elementDescriptor.getColumns().size() == 1;
|
||||
final Column keyColumn = elementDescriptor.getColumns().get( 0 );
|
||||
|
||||
// collectionTableName.keyColumnName -> targetTableName.targetColumnName
|
||||
|
||||
final SelectableMapping keySelectableMapping = SelectableMappingImpl.from(
|
||||
collectionTableName,
|
||||
keyColumn,
|
||||
basicIdMapping.getJdbcMapping(),
|
||||
creationProcess.getCreationContext().getTypeConfiguration(),
|
||||
true,
|
||||
false,
|
||||
creationProcess.getCreationContext().getSessionFactory().getJdbcServices().getDialect(),
|
||||
creationProcess.getSqmFunctionRegistry()
|
||||
);
|
||||
|
||||
final BasicAttributeMapping keyModelPart = BasicAttributeMapping.withSelectableMapping(
|
||||
getAssociatedEntityMappingType(),
|
||||
basicIdMapping,
|
||||
basicIdMapping.getPropertyAccess(),
|
||||
NoValueGeneration.INSTANCE,
|
||||
true,
|
||||
false,
|
||||
keySelectableMapping
|
||||
);
|
||||
|
||||
return new SimpleForeignKeyDescriptor(
|
||||
// the key
|
||||
keyModelPart,
|
||||
// the target
|
||||
basicIdMapping,
|
||||
// refers to primary key
|
||||
true,
|
||||
// has a constraint
|
||||
true,
|
||||
// do not swap the sides
|
||||
false
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
private static ModelPart resolveNamedTargetPart(
|
||||
String targetPartName,
|
||||
EntityMappingType entityMappingType,
|
||||
|
|
|
@ -46,8 +46,6 @@ import org.hibernate.usertype.UserVersionType;
|
|||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
// todo (6.0) : ^^ this introduces a problem in code that relies on `instanceof` checks
|
||||
// against any of these interfaces when the wrapped type does not
|
||||
public class CustomType<J>
|
||||
extends AbstractType
|
||||
implements ConvertedBasicType<J>, ProcedureParameterNamedBinder<J>, ProcedureParameterExtractionAware<J> {
|
||||
|
|
|
@ -17,7 +17,6 @@ import org.hibernate.envers.NotAudited;
|
|||
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
|
||||
import org.hibernate.orm.test.envers.Priority;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -100,7 +99,6 @@ public class ListHashcodeChangeTest extends BaseEnversJPAFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-15393", message = "Work for HHH-15393 (write-paths) causes a failure" )
|
||||
// tests that Author has 3 books.
|
||||
public void testAuthorState() {
|
||||
EntityManager entityManager = getEntityManager();
|
||||
|
@ -258,7 +256,8 @@ public class ListHashcodeChangeTest extends BaseEnversJPAFunctionalTestCase {
|
|||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "author_book",
|
||||
joinColumns = @JoinColumn(name = "book_id"), inverseJoinColumns = @JoinColumn(name="author_id",nullable = false))
|
||||
joinColumns = @JoinColumn(name = "book_id"),
|
||||
inverseJoinColumns = @JoinColumn(name="author_id",nullable = false))
|
||||
@NotAudited
|
||||
private Author author;
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.hibernate.envers.NotAudited;
|
|||
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
|
||||
import org.hibernate.orm.test.envers.Priority;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -101,7 +100,6 @@ public class SetHashcodeChangeTest extends BaseEnversJPAFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-15393", message = "Work for HHH-15393 (write-paths) causes a failure" )
|
||||
// tests that Author has 3 books.
|
||||
public void testAuthorState() {
|
||||
EntityManager entityManager = getEntityManager();
|
||||
|
|
Loading…
Reference in New Issue