diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java index fb779e95..1c165b79 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java @@ -353,9 +353,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { // If the root aggregate has a version property, increment it. previousVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(instance, persistentEntity, converter); - Assert.notNull(previousVersion, "The root aggregate cannot be updated because the version property is null."); - - long newVersion = previousVersion.longValue() + 1; + long newVersion = (previousVersion == null ? 0 : previousVersion.longValue()) + 1; preparedInstance = RelationalEntityVersionUtils.setVersionNumberOnEntity(instance, newVersion, persistentEntity, converter); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java index 206820bf..35f5fe61 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java @@ -53,6 +53,7 @@ import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.annotation.ReadOnlyProperty; import org.springframework.data.annotation.Version; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Persistable; import org.springframework.data.domain.Sort; import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.JdbcConverter; @@ -258,14 +259,15 @@ class JdbcAggregateTemplateIntegrationTests { } @Test // GH-821 - @EnabledOnFeature({SUPPORTS_QUOTED_IDS, SUPPORTS_NULL_PRECEDENCE}) + @EnabledOnFeature({ SUPPORTS_QUOTED_IDS, SUPPORTS_NULL_PRECEDENCE }) void saveAndLoadManyEntitiesWithReferencedEntitySortedWithNullPrecedence() { template.save(createLegoSet(null)); template.save(createLegoSet("Star")); template.save(createLegoSet("Frozen")); - Iterable reloadedLegoSets = template.findAll(LegoSet.class, Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST))); + Iterable reloadedLegoSets = template.findAll(LegoSet.class, + Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST))); assertThat(reloadedLegoSets) // .extracting("name") // @@ -843,7 +845,8 @@ class JdbcAggregateTemplateIntegrationTests { assertThat(updatedRoot.version).isEqualTo(1L); // Expect only one assignment of the version to AggregateWithImmutableVersion - assertThat(AggregateWithImmutableVersion.constructorInvocations).containsOnly(new ConstructorInvocation(savedRoot.id, updatedRoot.version)); + assertThat(AggregateWithImmutableVersion.constructorInvocations) + .containsOnly(new ConstructorInvocation(savedRoot.id, updatedRoot.version)); } @Test // DATAJDBC-219 Test that a delete with a version attribute works as expected. @@ -908,6 +911,16 @@ class JdbcAggregateTemplateIntegrationTests { saveAndUpdateAggregateWithPrimitiveVersion(new AggregateWithPrimitiveShortVersion(), Number::shortValue); } + @Test // GH-1254 + void saveAndUpdateAggregateWithIdAndNullVersion() { + + PersistableVersionedAggregate aggregate = new PersistableVersionedAggregate(); + aggregate.setVersion(null); + aggregate.setId(23L); + + assertThatThrownBy(() -> template.save(aggregate)).isInstanceOf(DbActionExecutionException.class); + } + @Test // DATAJDBC-462 @EnabledOnFeature(SUPPORTS_QUOTED_IDS) void resavingAnUnversionedEntity() { @@ -1075,18 +1088,15 @@ class JdbcAggregateTemplateIntegrationTests { @Column("id4") @Id private Long id; String name; - @MappedCollection(idColumn = "LIST_PARENT") - List content = new ArrayList<>(); + @MappedCollection(idColumn = "LIST_PARENT") List content = new ArrayList<>(); } @Table("LIST_PARENT") static class ListParentAllArgs { - @Column("id4") @Id - private final Long id; + @Column("id4") @Id private final Long id; private final String name; - @MappedCollection(idColumn = "LIST_PARENT") - private final List content = new ArrayList<>(); + @MappedCollection(idColumn = "LIST_PARENT") private final List content = new ArrayList<>(); @PersistenceConstructor ListParentAllArgs(Long id, String name, List content) { @@ -1247,6 +1257,20 @@ class JdbcAggregateTemplateIntegrationTests { abstract void setVersion(Number newVersion); } + @Data + @Table("VERSIONED_AGGREGATE") + static class PersistableVersionedAggregate implements Persistable { + + @Id private Long id; + + @Version Long version; + + @Override + public boolean isNew() { + return getId() == null; + } + } + @Value @With @Table("VERSIONED_AGGREGATE")