HHH-12671 - Fix persisting generated properties on identity insert
This commit is contained in:
parent
607e51617e
commit
2211e61b04
|
@ -2753,9 +2753,40 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
// add normal properties except lobs
|
||||
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, 0 ) && !lobProperties.contains( i ) ) {
|
||||
// this property belongs on the table and is to be inserted
|
||||
insert.addColumns( getPropertyColumnNames( i ), propertyColumnInsertable[i], propertyColumnWriters[i] );
|
||||
if ( isPropertyOfTable( i, 0 ) && !lobProperties.contains( i ) ) {
|
||||
final InDatabaseValueGenerationStrategy generationStrategy = entityMetamodel.getInDatabaseValueGenerationStrategies()[i];
|
||||
|
||||
if ( includeProperty[i] ) {
|
||||
insert.addColumns(
|
||||
getPropertyColumnNames( i ),
|
||||
propertyColumnInsertable[i],
|
||||
propertyColumnWriters[i]
|
||||
);
|
||||
}
|
||||
else if ( generationStrategy != null &&
|
||||
generationStrategy.getGenerationTiming().includesInsert() &&
|
||||
generationStrategy.referenceColumnsInSql() ) {
|
||||
|
||||
final String[] values;
|
||||
|
||||
if ( generationStrategy.getReferencedColumnValues() == null ) {
|
||||
values = propertyColumnWriters[i];
|
||||
}
|
||||
else {
|
||||
values = new String[propertyColumnWriters[i].length];
|
||||
|
||||
for ( int j = 0; j < values.length; j++ ) {
|
||||
values[j] = ( generationStrategy.getReferencedColumnValues()[j] != null ) ?
|
||||
generationStrategy.getReferencedColumnValues()[j] :
|
||||
propertyColumnWriters[i][j];
|
||||
}
|
||||
}
|
||||
insert.addColumns(
|
||||
getPropertyColumnNames( i ),
|
||||
propertyColumnInsertable[i],
|
||||
values
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* 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.test.generated;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.MonthDay;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.OffsetTime;
|
||||
import java.time.Year;
|
||||
import java.time.YearMonth;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.ColumnDefault;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.Generated;
|
||||
import org.hibernate.annotations.GenerationTime;
|
||||
import org.hibernate.annotations.GeneratorType;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
import org.hibernate.annotations.ValueGenerationType;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.tuple.AnnotationValueGeneration;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.ValueGenerator;
|
||||
|
||||
import org.hibernate.testing.DialectChecks;
|
||||
import org.hibernate.testing.RequiresDialectFeature;
|
||||
import org.hibernate.testing.SkipForDialect;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@SkipForDialect(value = SybaseDialect.class, comment = "CURRENT_TIMESTAMP not supported as default value in Sybase")
|
||||
@SkipForDialect(value = MySQLDialect.class, comment = "See HHH-10196", strictMatching = false)
|
||||
@RequiresDialectFeature(DialectChecks.SupportsIdentityColumns.class)
|
||||
public class DefaultGeneratedValueIdentityTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { TheEntity.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCleanupTestDataUsingBulkDelete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-12671" )
|
||||
public void testGenerationWithIdentityInsert() {
|
||||
final TheEntity theEntity = new TheEntity( 1 );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
assertNull( theEntity.createdDate );
|
||||
assertNull( theEntity.alwaysDate );
|
||||
assertNull( theEntity.vmCreatedDate );
|
||||
assertNull( theEntity.vmCreatedSqlDate );
|
||||
assertNull( theEntity.vmCreatedSqlTime );
|
||||
assertNull( theEntity.vmCreatedSqlTimestamp );
|
||||
|
||||
assertNull( theEntity.vmCreatedSqlLocalDate );
|
||||
assertNull( theEntity.vmCreatedSqlLocalTime );
|
||||
assertNull( theEntity.vmCreatedSqlLocalDateTime );
|
||||
assertNull( theEntity.vmCreatedSqlMonthDay );
|
||||
assertNull( theEntity.vmCreatedSqlOffsetDateTime );
|
||||
assertNull( theEntity.vmCreatedSqlOffsetTime );
|
||||
assertNull( theEntity.vmCreatedSqlYear );
|
||||
assertNull( theEntity.vmCreatedSqlYearMonth );
|
||||
assertNull( theEntity.vmCreatedSqlZonedDateTime );
|
||||
assertNull( theEntity.dbCreatedDate );
|
||||
|
||||
assertNull( theEntity.name );
|
||||
session.save( theEntity );
|
||||
|
||||
assertNotNull( theEntity.createdDate );
|
||||
assertNotNull( theEntity.alwaysDate );
|
||||
assertNotNull( theEntity.vmCreatedDate );
|
||||
assertNotNull( theEntity.vmCreatedSqlDate );
|
||||
assertNotNull( theEntity.vmCreatedSqlTime );
|
||||
assertNotNull( theEntity.vmCreatedSqlTimestamp );
|
||||
assertNotNull( theEntity.vmCreatedSqlLocalDate );
|
||||
assertNotNull( theEntity.vmCreatedSqlLocalTime );
|
||||
assertNotNull( theEntity.vmCreatedSqlLocalDateTime );
|
||||
assertNotNull( theEntity.vmCreatedSqlMonthDay );
|
||||
assertNotNull( theEntity.vmCreatedSqlOffsetDateTime );
|
||||
assertNotNull( theEntity.vmCreatedSqlOffsetTime );
|
||||
assertNotNull( theEntity.vmCreatedSqlYear );
|
||||
assertNotNull( theEntity.vmCreatedSqlYearMonth );
|
||||
assertNotNull( theEntity.vmCreatedSqlZonedDateTime );
|
||||
assertNotNull( theEntity.dbCreatedDate );
|
||||
assertNotNull( theEntity.name );
|
||||
} );
|
||||
|
||||
assertNotNull( theEntity.createdDate );
|
||||
assertNotNull( theEntity.alwaysDate );
|
||||
assertEquals( "Bob", theEntity.name );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
TheEntity _theEntity = session.get( TheEntity.class, 1 );
|
||||
assertNotNull( _theEntity.createdDate );
|
||||
assertNotNull( _theEntity.alwaysDate );
|
||||
assertNotNull( _theEntity.vmCreatedDate );
|
||||
assertNotNull( _theEntity.vmCreatedSqlDate );
|
||||
assertNotNull( _theEntity.vmCreatedSqlTime );
|
||||
assertNotNull( _theEntity.vmCreatedSqlTimestamp );
|
||||
assertNotNull( _theEntity.vmCreatedSqlLocalDate );
|
||||
assertNotNull( _theEntity.vmCreatedSqlLocalTime );
|
||||
assertNotNull( _theEntity.vmCreatedSqlLocalDateTime );
|
||||
assertNotNull( _theEntity.vmCreatedSqlMonthDay );
|
||||
assertNotNull( _theEntity.vmCreatedSqlOffsetDateTime );
|
||||
assertNotNull( _theEntity.vmCreatedSqlOffsetTime );
|
||||
assertNotNull( _theEntity.vmCreatedSqlYear );
|
||||
assertNotNull( _theEntity.vmCreatedSqlYearMonth );
|
||||
assertNotNull( _theEntity.vmCreatedSqlZonedDateTime );
|
||||
assertNotNull( _theEntity.dbCreatedDate );
|
||||
assertEquals( "Bob", _theEntity.name );
|
||||
|
||||
_theEntity.lastName = "Smith";
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity( name = "TheEntity" )
|
||||
private static class TheEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Generated( GenerationTime.INSERT )
|
||||
@ColumnDefault( "CURRENT_TIMESTAMP" )
|
||||
@Column( nullable = false )
|
||||
private Date createdDate;
|
||||
|
||||
@Generated( GenerationTime.ALWAYS )
|
||||
@ColumnDefault( "CURRENT_TIMESTAMP" )
|
||||
@Column( nullable = false )
|
||||
private Calendar alwaysDate;
|
||||
|
||||
@CreationTimestamp
|
||||
private Date vmCreatedDate;
|
||||
|
||||
@CreationTimestamp
|
||||
private Calendar vmCreatedCalendar;
|
||||
|
||||
@CreationTimestamp
|
||||
private java.sql.Date vmCreatedSqlDate;
|
||||
|
||||
@CreationTimestamp
|
||||
private Time vmCreatedSqlTime;
|
||||
|
||||
@CreationTimestamp
|
||||
private Timestamp vmCreatedSqlTimestamp;
|
||||
|
||||
@CreationTimestamp
|
||||
private Instant vmCreatedSqlInstant;
|
||||
|
||||
@CreationTimestamp
|
||||
private LocalDate vmCreatedSqlLocalDate;
|
||||
|
||||
@CreationTimestamp
|
||||
private LocalTime vmCreatedSqlLocalTime;
|
||||
|
||||
@CreationTimestamp
|
||||
private LocalDateTime vmCreatedSqlLocalDateTime;
|
||||
|
||||
@CreationTimestamp
|
||||
private MonthDay vmCreatedSqlMonthDay;
|
||||
|
||||
@CreationTimestamp
|
||||
private OffsetDateTime vmCreatedSqlOffsetDateTime;
|
||||
|
||||
@CreationTimestamp
|
||||
private OffsetTime vmCreatedSqlOffsetTime;
|
||||
|
||||
@CreationTimestamp
|
||||
private Year vmCreatedSqlYear;
|
||||
|
||||
@CreationTimestamp
|
||||
private YearMonth vmCreatedSqlYearMonth;
|
||||
|
||||
@CreationTimestamp
|
||||
private ZonedDateTime vmCreatedSqlZonedDateTime;
|
||||
|
||||
@FunctionCreationTimestamp
|
||||
private Date dbCreatedDate;
|
||||
|
||||
@UpdateTimestamp
|
||||
private Timestamp updated;
|
||||
|
||||
@GeneratorType( type = MyVmValueGenerator.class, when = GenerationTime.INSERT )
|
||||
private String name;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String lastName;
|
||||
|
||||
private TheEntity() {
|
||||
}
|
||||
|
||||
private TheEntity(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyVmValueGenerator implements ValueGenerator<String> {
|
||||
|
||||
@Override
|
||||
public String generateValue(Session session, Object owner) {
|
||||
return "Bob";
|
||||
}
|
||||
}
|
||||
|
||||
@ValueGenerationType(generatedBy = FunctionCreationValueGeneration.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface FunctionCreationTimestamp {
|
||||
}
|
||||
|
||||
public static class FunctionCreationValueGeneration
|
||||
implements AnnotationValueGeneration<FunctionCreationTimestamp> {
|
||||
|
||||
@Override
|
||||
public void initialize(FunctionCreationTimestamp annotation, Class<?> propertyType) {
|
||||
}
|
||||
|
||||
public GenerationTiming getGenerationTiming() {
|
||||
// its creation...
|
||||
return GenerationTiming.INSERT;
|
||||
}
|
||||
|
||||
public ValueGenerator<?> getValueGenerator() {
|
||||
// no in-memory generation
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean referenceColumnInSql() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
||||
return "current_timestamp";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue