Handle insert-select for entities with generators that do not support bulk insertion
This commit is contained in:
parent
49e9696ced
commit
ed1cea6ba1
|
@ -93,6 +93,7 @@ import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
|
|||
import org.hibernate.query.sqm.tree.insert.SqmValues;
|
||||
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelection;
|
||||
import org.hibernate.query.sqm.tree.update.SqmAssignment;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
|
@ -371,10 +372,10 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
else {
|
||||
final SqmInsertSelectStatement<R> statement = (SqmInsertSelectStatement<R>) sqmStatement;
|
||||
final List<SqmSelection<?>> selections = statement.getSelectQueryPart()
|
||||
final List<SqmSelectableNode<?>> selections = statement.getSelectQueryPart()
|
||||
.getFirstQuerySpec()
|
||||
.getSelectClause()
|
||||
.getSelections();
|
||||
.getSelectionItems();
|
||||
verifyInsertTypesMatch( hqlString, insertionTargetPaths, selections );
|
||||
statement.getSelectQueryPart().validateQueryStructureAndFetchOwners();
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.engine.FetchTiming;
|
|||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.OptimizableGenerator;
|
||||
import org.hibernate.id.PostInsertIdentifierGenerator;
|
||||
|
@ -288,7 +289,10 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
|
||||
final IdentifierGenerator identifierGenerator = entityDescriptor.getEntityPersister().getIdentifierGenerator();
|
||||
final List<Assignment> assignments = assignmentsByTable.get( updatingTableReference );
|
||||
if ( ( assignments == null || assignments.isEmpty() ) && !( identifierGenerator instanceof PostInsertIdentifierGenerator ) ) {
|
||||
if ( ( assignments == null || assignments.isEmpty() )
|
||||
&& !( identifierGenerator instanceof PostInsertIdentifierGenerator )
|
||||
&& ( !( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator )
|
||||
|| ( (BulkInsertionCapableIdentifierGenerator) identifierGenerator ).supportsBulkInsertionIdentifierGeneration() ) ) {
|
||||
throw new IllegalStateException( "There must be at least a single root table assignment" );
|
||||
}
|
||||
|
||||
|
@ -312,24 +316,26 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
querySpec.getFromClause().addRoot( temporaryTableGroup );
|
||||
final InsertStatement insertStatement = new InsertStatement( dmlTableReference );
|
||||
insertStatement.setSourceSelectStatement( querySpec );
|
||||
for ( Assignment assignment : assignments ) {
|
||||
insertStatement.addTargetColumnReferences( assignment.getAssignable().getColumnReferences() );
|
||||
for ( ColumnReference columnReference : assignment.getAssignable().getColumnReferences() ) {
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
columnReference.getColumnExpression(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
columnReference.getJdbcMapping(),
|
||||
sessionFactory
|
||||
)
|
||||
)
|
||||
);
|
||||
if ( assignments != null ) {
|
||||
for ( Assignment assignment : assignments ) {
|
||||
insertStatement.addTargetColumnReferences( assignment.getAssignable().getColumnReferences() );
|
||||
for ( ColumnReference columnReference : assignment.getAssignable().getColumnReferences() ) {
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
columnReference.getColumnExpression(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
columnReference.getJdbcMapping(),
|
||||
sessionFactory
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
|
@ -394,114 +400,113 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
}
|
||||
else {
|
||||
entityTableToRootIdentity = null;
|
||||
if ( identifierGenerator instanceof OptimizableGenerator ) {
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
|
||||
// If the generator uses an optimizer, we have to generate the identifiers for the new rows
|
||||
// but only if the target paths don't already contain the id
|
||||
if ( optimizer != null && optimizer.getIncrementSize() > 1 && insertStatement.getTargetColumnReferences()
|
||||
.stream()
|
||||
.noneMatch( c -> keyColumns[0].equals( c.getColumnExpression() ) ) ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
// if the target paths don't already contain the id, and we need identifier generation,
|
||||
// then we load update rows from the temporary table with the generated identifiers,
|
||||
// to then insert into the target tables in once statement
|
||||
if ( needsIdentifierGeneration( identifierGenerator )
|
||||
&& insertStatement.getTargetColumnReferences()
|
||||
.stream()
|
||||
.noneMatch( c -> keyColumns[0].equals( c.getColumnExpression() ) ) ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
|
||||
final JdbcParameter rowNumber = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final JdbcParameter rootIdentity = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final List<Assignment> temporaryTableAssignments = new ArrayList<>( 1 );
|
||||
final ColumnReference idColumnReference = new ColumnReference(
|
||||
(String) null,
|
||||
identifierMapping,
|
||||
sessionFactory
|
||||
);
|
||||
temporaryTableAssignments.add(
|
||||
new Assignment(
|
||||
idColumnReference,
|
||||
rootIdentity
|
||||
)
|
||||
);
|
||||
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(
|
||||
entityTable.getColumns().size() - 1
|
||||
);
|
||||
final UpdateStatement updateStatement = new UpdateStatement(
|
||||
temporaryTableReference,
|
||||
temporaryTableAssignments,
|
||||
new ComparisonPredicate(
|
||||
new ColumnReference(
|
||||
(String) null,
|
||||
rowNumberColumn.getColumnName(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
rowNumberColumn.getJdbcMapping(),
|
||||
sessionFactory
|
||||
),
|
||||
ComparisonOperator.EQUAL,
|
||||
rowNumber
|
||||
)
|
||||
);
|
||||
|
||||
final JdbcUpdate jdbcUpdate = jdbcServices.getJdbcEnvironment()
|
||||
.getSqlAstTranslatorFactory()
|
||||
.buildUpdateTranslator( sessionFactory, updateStatement )
|
||||
.translate( null, executionContext.getQueryOptions() );
|
||||
final JdbcParameterBindings updateBindings = new JdbcParameterBindingsImpl( 2 );
|
||||
|
||||
for ( int i = 0; i < rows; i++ ) {
|
||||
updateBindings.addBinding(
|
||||
rowNumber,
|
||||
new JdbcParameterBindingImpl(
|
||||
final JdbcParameter rowNumber = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final JdbcParameter rootIdentity = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final List<Assignment> temporaryTableAssignments = new ArrayList<>( 1 );
|
||||
final ColumnReference idColumnReference = new ColumnReference(
|
||||
(String) null,
|
||||
identifierMapping,
|
||||
sessionFactory
|
||||
);
|
||||
temporaryTableAssignments.add(
|
||||
new Assignment(
|
||||
idColumnReference,
|
||||
rootIdentity
|
||||
)
|
||||
);
|
||||
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(
|
||||
entityTable.getColumns().size() - 1
|
||||
);
|
||||
final UpdateStatement updateStatement = new UpdateStatement(
|
||||
temporaryTableReference,
|
||||
temporaryTableAssignments,
|
||||
new ComparisonPredicate(
|
||||
new ColumnReference(
|
||||
(String) null,
|
||||
rowNumberColumn.getColumnName(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
rowNumberColumn.getJdbcMapping(),
|
||||
i + 1
|
||||
)
|
||||
);
|
||||
updateBindings.addBinding(
|
||||
rootIdentity,
|
||||
new JdbcParameterBindingImpl(
|
||||
identifierMapping.getJdbcMapping(),
|
||||
identifierGenerator.generate(
|
||||
executionContext.getSession(),
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
jdbcUpdate,
|
||||
updateBindings,
|
||||
sql -> executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {
|
||||
},
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
sessionFactory
|
||||
),
|
||||
ComparisonOperator.EQUAL,
|
||||
rowNumber
|
||||
)
|
||||
);
|
||||
|
||||
insertStatement.addTargetColumnReferences(
|
||||
new ColumnReference(
|
||||
(String) null,
|
||||
keyColumns[0],
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
identifierMapping.getJdbcMapping(),
|
||||
sessionFactory
|
||||
final JdbcUpdate jdbcUpdate = jdbcServices.getJdbcEnvironment()
|
||||
.getSqlAstTranslatorFactory()
|
||||
.buildUpdateTranslator( sessionFactory, updateStatement )
|
||||
.translate( null, executionContext.getQueryOptions() );
|
||||
final JdbcParameterBindings updateBindings = new JdbcParameterBindingsImpl( 2 );
|
||||
|
||||
for ( int i = 0; i < rows; i++ ) {
|
||||
updateBindings.addBinding(
|
||||
rowNumber,
|
||||
new JdbcParameterBindingImpl(
|
||||
rowNumberColumn.getJdbcMapping(),
|
||||
i + 1
|
||||
)
|
||||
);
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
idColumnReference.getColumnExpression(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
idColumnReference.getJdbcMapping(),
|
||||
sessionFactory
|
||||
updateBindings.addBinding(
|
||||
rootIdentity,
|
||||
new JdbcParameterBindingImpl(
|
||||
identifierMapping.getJdbcMapping(),
|
||||
identifierGenerator.generate(
|
||||
executionContext.getSession(),
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
jdbcUpdate,
|
||||
updateBindings,
|
||||
sql -> executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {
|
||||
},
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
|
||||
insertStatement.addTargetColumnReferences(
|
||||
new ColumnReference(
|
||||
(String) null,
|
||||
keyColumns[0],
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
identifierMapping.getJdbcMapping(),
|
||||
sessionFactory
|
||||
)
|
||||
);
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
idColumnReference.getColumnExpression(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
idColumnReference.getJdbcMapping(),
|
||||
sessionFactory
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,6 +613,17 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
}
|
||||
}
|
||||
|
||||
private boolean needsIdentifierGeneration(IdentifierGenerator identifierGenerator) {
|
||||
if ( !( identifierGenerator instanceof OptimizableGenerator ) ) {
|
||||
return false;
|
||||
}
|
||||
// If the generator uses an optimizer or is not bulk insertion capable, we have to generate identifiers for the new rows,
|
||||
// as that couldn't have been done through a SQL expression
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
|
||||
return optimizer != null && optimizer.getIncrementSize() > 1 || identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator
|
||||
&& !( (BulkInsertionCapableIdentifierGenerator) identifierGenerator ).supportsBulkInsertionIdentifierGeneration();
|
||||
}
|
||||
|
||||
private void insertTable(
|
||||
String tableExpression,
|
||||
String[] keyColumns,
|
||||
|
|
|
@ -1259,18 +1259,48 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
identifierGenerator = null;
|
||||
}
|
||||
else if ( identifierGenerator != null ) {
|
||||
// When we have an identifier generator, we somehow must list the identifier column in the insert statement.
|
||||
final boolean addIdColumn;
|
||||
if ( sqmStatement instanceof SqmInsertValuesStatement<?> ) {
|
||||
// For an InsertValuesStatement, we can just list the column, as we can inject a parameter in the VALUES clause.
|
||||
addIdColumn = true;
|
||||
}
|
||||
else if ( !( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator ) ) {
|
||||
// For non-identity generators that don't implement BulkInsertionCapableIdentifierGenerator, there is nothing we can do
|
||||
addIdColumn = false;
|
||||
}
|
||||
else {
|
||||
// Same condition as in AdditionalInsertValues#applySelections
|
||||
final Optimizer optimizer;
|
||||
if ( identifierGenerator instanceof OptimizableGenerator
|
||||
&& ( optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer() ) != null
|
||||
&& optimizer.getIncrementSize() > 1
|
||||
|| !( (BulkInsertionCapableIdentifierGenerator) identifierGenerator ).supportsBulkInsertionIdentifierGeneration() ) {
|
||||
// If the dialect does not support window functions, we don't need the id column in the temporary table insert
|
||||
// because we will make use of the special "rn_" column that is auto-incremented and serves as temporary identifier for a row,
|
||||
// which is needed to control the generation of proper identifier values with the generator afterwards
|
||||
addIdColumn = creationContext.getSessionFactory().getJdbcServices().getDialect().supportsWindowFunctions();
|
||||
}
|
||||
else {
|
||||
// If the generator supports bulk insertion and the optimizer uses an increment size of 1,
|
||||
// we can list the column, because we can emit a SQL expression.
|
||||
addIdColumn = true;
|
||||
}
|
||||
}
|
||||
identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
final BasicValuedPathInterpretation<?> identifierPath = new BasicValuedPathInterpretation<>(
|
||||
new ColumnReference(
|
||||
rootTableGroup.resolveTableReference( identifierMapping.getContainingTableExpression() ),
|
||||
identifierMapping,
|
||||
getCreationContext().getSessionFactory()
|
||||
),
|
||||
rootTableGroup.getNavigablePath().append( identifierMapping.getPartName() ),
|
||||
identifierMapping,
|
||||
rootTableGroup
|
||||
);
|
||||
targetColumnReferenceConsumer.accept( identifierPath, identifierPath.getColumnReferences() );
|
||||
if ( addIdColumn ) {
|
||||
final BasicValuedPathInterpretation<?> identifierPath = new BasicValuedPathInterpretation<>(
|
||||
new ColumnReference(
|
||||
rootTableGroup.resolveTableReference( identifierMapping.getContainingTableExpression() ),
|
||||
identifierMapping,
|
||||
getCreationContext().getSessionFactory()
|
||||
),
|
||||
rootTableGroup.getNavigablePath().append( identifierMapping.getPartName() ),
|
||||
identifierMapping,
|
||||
rootTableGroup
|
||||
);
|
||||
targetColumnReferenceConsumer.accept( identifierPath, identifierPath.getColumnReferences() );
|
||||
}
|
||||
}
|
||||
|
||||
return new AdditionalInsertValues(
|
||||
|
@ -1340,15 +1370,19 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
if ( identifierGenerator != null ) {
|
||||
if ( identifierSelection == null ) {
|
||||
if ( !( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator )
|
||||
|| !( (BulkInsertionCapableIdentifierGenerator) identifierGenerator ).supportsBulkInsertionIdentifierGeneration() ) {
|
||||
if ( !( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator ) ) {
|
||||
throw new SemanticException(
|
||||
"SQM INSERT-SELECT without bulk insertion capable identifier generator: " + identifierGenerator );
|
||||
}
|
||||
if ( identifierGenerator instanceof OptimizableGenerator ) {
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
|
||||
if ( optimizer != null && optimizer.getIncrementSize() > 1 ) {
|
||||
if ( optimizer != null && optimizer.getIncrementSize() > 1
|
||||
|| !( (BulkInsertionCapableIdentifierGenerator) identifierGenerator ).supportsBulkInsertionIdentifierGeneration() ) {
|
||||
// This is a special case where we have a sequence with an optimizer
|
||||
// or a table based identifier generator
|
||||
if ( !sessionFactory.getJdbcServices().getDialect().supportsWindowFunctions() ) {
|
||||
return false;
|
||||
}
|
||||
final BasicType<Integer> rowNumberType = sessionFactory.getTypeConfiguration()
|
||||
.getBasicTypeForJavaType( Integer.class );
|
||||
identifierSelection = new SqlSelectionImpl(
|
||||
|
|
|
@ -29,11 +29,11 @@ import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
|
|||
*/
|
||||
@Incubating
|
||||
public class SqmInsertSelectStatement<T> extends AbstractSqmInsertStatement<T> implements JpaCriteriaInsertSelect<T> {
|
||||
private SqmQueryPart<T> selectQueryPart;
|
||||
private SqmQueryPart<?> selectQueryPart;
|
||||
|
||||
public SqmInsertSelectStatement(SqmRoot<T> targetRoot, NodeBuilder nodeBuilder) {
|
||||
super( targetRoot, SqmQuerySource.HQL, nodeBuilder );
|
||||
this.selectQueryPart = new SqmQuerySpec<T>( nodeBuilder );
|
||||
this.selectQueryPart = new SqmQuerySpec<>( nodeBuilder );
|
||||
}
|
||||
|
||||
public SqmInsertSelectStatement(Class<T> targetEntity, NodeBuilder nodeBuilder) {
|
||||
|
@ -58,7 +58,7 @@ public class SqmInsertSelectStatement<T> extends AbstractSqmInsertStatement<T> i
|
|||
boolean withRecursiveCte,
|
||||
SqmRoot<T> target,
|
||||
List<SqmPath<?>> insertionTargetPaths,
|
||||
SqmQueryPart<T> selectQueryPart) {
|
||||
SqmQueryPart<?> selectQueryPart) {
|
||||
super( builder, querySource, parameters, cteStatements, withRecursiveCte, target, insertionTargetPaths );
|
||||
this.selectQueryPart = selectQueryPart;
|
||||
}
|
||||
|
@ -84,11 +84,11 @@ public class SqmInsertSelectStatement<T> extends AbstractSqmInsertStatement<T> i
|
|||
);
|
||||
}
|
||||
|
||||
public SqmQueryPart<T> getSelectQueryPart() {
|
||||
public SqmQueryPart<?> getSelectQueryPart() {
|
||||
return selectQueryPart;
|
||||
}
|
||||
|
||||
public void setSelectQueryPart(SqmQueryPart<T> selectQueryPart) {
|
||||
public void setSelectQueryPart(SqmQueryPart<?> selectQueryPart) {
|
||||
this.selectQueryPart = selectQueryPart;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
package org.hibernate.orm.test.query.criteria;
|
||||
|
||||
import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder;
|
||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
|
||||
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.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
|
@ -21,22 +21,25 @@ import jakarta.persistence.Entity;
|
|||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Tuple;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel(annotatedClasses = InsertSelectTests.AnEntity.class)
|
||||
@SessionFactory
|
||||
@Disabled(value = "Disabled for now because this test fails on MySQL and Sybase (SequenceStyleGenerator is not bulk capable on those)")
|
||||
public class InsertSelectTests {
|
||||
@Test
|
||||
public void simpleTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
session.persist( new AnEntity( "test" ) );
|
||||
final SqmCriteriaNodeBuilder criteriaBuilder = (SqmCriteriaNodeBuilder) session.getCriteriaBuilder();
|
||||
final SqmInsertSelectStatement<AnEntity> insertSelect = criteriaBuilder.createCriteriaInsertSelect( AnEntity.class );
|
||||
final SqmSelectStatement<AnEntity> select = criteriaBuilder.createQuery( AnEntity.class );
|
||||
final SqmSelectStatement<Tuple> select = criteriaBuilder.createQuery( Tuple.class );
|
||||
insertSelect.addInsertTargetStateField( insertSelect.getTarget().get( "name" ) );
|
||||
final SqmRoot<AnEntity> root = select.from( AnEntity.class );
|
||||
select.multiselect( root.get( "name" ) );
|
||||
insertSelect.setSelectQueryPart( select.getQuerySpec() );
|
||||
select.from( AnEntity.class );
|
||||
session.createMutationQuery( insertSelect ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
@ -55,6 +58,10 @@ public class InsertSelectTests {
|
|||
// for use by Hibernate
|
||||
}
|
||||
|
||||
public AnEntity(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public AnEntity(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
|
|
Loading…
Reference in New Issue