Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.StringTokenizer;
import java.util.function.Function;

import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
Expand Down Expand Up @@ -662,28 +663,32 @@ private static void createValueBindings(
if ( parameterType == null ) {
throw new SqlTreeCreationException( "Unable to interpret mapping-model type for Query parameter : " + domainParam );
}
else if ( parameterType instanceof PluralAttributeMapping ) {
else if ( parameterType instanceof PluralAttributeMapping pluralAttributeMapping ) {
// Default to the collection element
parameterType = ( (PluralAttributeMapping) parameterType ).getElementDescriptor();
parameterType = pluralAttributeMapping.getElementDescriptor();
}

if ( parameterType instanceof EntityIdentifierMapping ) {
final EntityIdentifierMapping identifierMapping = (EntityIdentifierMapping) parameterType;
if ( parameterType instanceof EntityIdentifierMapping identifierMapping) {
final EntityMappingType entityMapping = identifierMapping.findContainingEntityMapping();
if ( entityMapping.getRepresentationStrategy().getInstantiator().isInstance( bindValue, session.getFactory() ) ) {
bindValue = identifierMapping.getIdentifierIfNotUnsaved( bindValue, session );
}
}
else if ( parameterType instanceof EntityMappingType ) {
final EntityIdentifierMapping identifierMapping = ( (EntityMappingType) parameterType ).getIdentifierMapping();
else if ( parameterType instanceof EntityMappingType entityMappingType ) {
jdbcParameterBindings.addAffectedTableName(
entityMappingType.getEntityPersister().getTableName()
);
final EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping();
final EntityMappingType entityMapping = identifierMapping.findContainingEntityMapping();
parameterType = identifierMapping;
if ( entityMapping.getRepresentationStrategy().getInstantiator().isInstance( bindValue, session.getFactory() ) ) {
bindValue = identifierMapping.getIdentifierIfNotUnsaved( bindValue, session );
}
}
else if ( parameterType instanceof EntityAssociationMapping ) {
EntityAssociationMapping association = (EntityAssociationMapping) parameterType;
else if ( parameterType instanceof EntityAssociationMapping association) {
jdbcParameterBindings.addAffectedTableName(
association.getAssociatedEntityMappingType().getEntityPersister().getTableName()
);
if ( association.getSideNature() == ForeignKeyDescriptor.Nature.TARGET ) {
// If the association is the target, we must use the identifier of the EntityMappingType
bindValue = association.getAssociatedEntityMappingType().getIdentifierMapping()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,9 @@ private static CteContainer matchCteContainerByStatement(final Statement stmt, f
public T translate(JdbcParameterBindings jdbcParameterBindings, QueryOptions queryOptions) {
try {
this.jdbcParameterBindings = jdbcParameterBindings;
if ( jdbcParameterBindings != null && jdbcParameterBindings.getAffectedTableNames() != null ) {
affectedTableNames.addAll( jdbcParameterBindings.getAffectedTableNames() );
}

final Statement statement = statementStack.pop();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;

import org.hibernate.dialect.Dialect;
Expand All @@ -37,6 +39,7 @@
*/
public class JdbcParameterBindingsImpl implements JdbcParameterBindings {
private Map<JdbcParameter, JdbcParameterBinding> bindingMap;
private Set<String> affectedTableName;

public JdbcParameterBindingsImpl(int expectedParameterCount) {
if ( expectedParameterCount > 0 ) {
Expand Down Expand Up @@ -185,4 +188,17 @@ public void clear() {
bindingMap.clear();
}
}

@Override
public Set<String> getAffectedTableNames() {
return affectedTableName;
}

@Override
public void addAffectedTableName(String tableName) {
if ( affectedTableName == null ) {
affectedTableName = new HashSet<>( bindingMap.size() );
}
affectedTableName.add( tableName );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.function.BiConsumer;

import org.hibernate.engine.spi.SharedSessionContractImplementor;
Expand Down Expand Up @@ -106,4 +107,12 @@ private void createAndAddBinding(
)
);
}

default Set<String> getAffectedTableNames(){
return null;
}

default void addAffectedTableName(String tableName){

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package org.hibernate.orm.test.flush;

import org.hibernate.testing.jdbc.SQLStatementInspector;
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;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;


@DomainModel(
annotatedClasses = {
AutoFlushOnUpdateQueryTest.FruitLogEntry.class,
AutoFlushOnUpdateQueryTest.Fruit.class,
}
)
@SessionFactory(
statementInspectorClass = SQLStatementInspector.class
)
public class AutoFlushOnUpdateQueryTest {

public static final String FRUIT_NAME = "Apple";

@BeforeEach
public void setUp(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist( new Fruit( FRUIT_NAME ) );
}
);
}

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

@Test
public void testFlushIsExecuted(SessionFactoryScope scope) {
SQLStatementInspector statementInspector = scope.getStatementInspector( SQLStatementInspector.class );
statementInspector.clear();
scope.inTransaction(
session -> {
Fruit fruit = session
.createQuery(
"select f from Fruit f where f.name = :name",
Fruit.class
).setParameter( "name", FRUIT_NAME ).getSingleResult();

FruitLogEntry logEntry = new FruitLogEntry( fruit, "foo" );
session.persist( logEntry );

session.createMutationQuery( "update Fruit f set f.logEntry = :logEntry where f.id = :fruitId" )
.setParameter( "logEntry", logEntry )
.setParameter( "fruitId", fruit.getId() ).executeUpdate();
}
);

scope.inTransaction(
session -> {
Fruit fruit = session
.createQuery(
"select f from Fruit f where f.name = :name",
Fruit.class
).setParameter( "name", FRUIT_NAME ).getSingleResult();
assertThat( fruit.getLogEntry() ).isNotNull();
}
);
}

@Entity(name = "Fruit")
public static class Fruit {

@Id
@GeneratedValue
private Long id;

private String name;

@OneToOne
private FruitLogEntry logEntry;

public Fruit() {
}

public Fruit(String name) {
this.name = name;
}

public Long getId() {
return id;
}

public String getName() {
return name;
}

public FruitLogEntry getLogEntry() {
return logEntry;
}
}

@Entity(name = "FruitLogEntry")
public static class FruitLogEntry {

@Id
@GeneratedValue
private Long id;

@OneToOne(mappedBy = "logEntry")
private Fruit fruit;

private String logComments;

public FruitLogEntry(Fruit fruit, String comment) {
this.fruit = fruit;
this.logComments = comment;
}

FruitLogEntry() {
}

public Long getId() {
return id;
}

public Fruit getFruit() {
return fruit;
}

public String getLogComments() {
return logComments;
}
}
}