Browse Source

DATAJDBC-417 - Fixed saving an entity containing a null embeddable with a reference to a further entity.

Constructing the DbActions assumed that the parent of a path exists (i.e. is not null) and created parent nodes.

Original pull request: #169.
pull/179/head
Jens Schauder 6 years ago committed by Mark Paluch
parent
commit
cf9b480ea2
No known key found for this signature in database
GPG Key ID: 51A00FA751B91849
  1. 15
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/WritingContext.java
  2. 65
      spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/RelationalEntityWriterUnitTests.java

15
spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/WritingContext.java

@ -202,7 +202,8 @@ class WritingContext {
} else { } else {
List<PathNode> pathNodes = nodesCache.get(path.getParentPath()); List<PathNode> pathNodes = nodesCache.getOrDefault(path.getParentPath(), Collections.emptyList());
pathNodes.forEach(parentNode -> { pathNodes.forEach(parentNode -> {
// todo: this should go into pathnode // todo: this should go into pathnode
@ -238,7 +239,17 @@ class WritingContext {
@Nullable @Nullable
private Object getFromRootValue(PersistentPropertyPath<RelationalPersistentProperty> path) { private Object getFromRootValue(PersistentPropertyPath<RelationalPersistentProperty> path) {
return path.getBaseProperty().getOwner().getPropertyAccessor(entity).getProperty(path);
if (path.getLength() == 0)
return entity;
Object parent = getFromRootValue(path.getParentPath());
if (parent == null) {
return null;
}
return context.getRequiredPersistentEntity(parent.getClass()).getPropertyAccessor(parent)
.getProperty(path.getRequiredLeafProperty());
} }
private List<PathNode> createNodes(PersistentPropertyPath<RelationalPersistentProperty> path, private List<PathNode> createNodes(PersistentPropertyPath<RelationalPersistentProperty> path,

65
spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/RelationalEntityWriterUnitTests.java

@ -29,7 +29,6 @@ import java.util.Set;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.PersistentPropertyPaths; import org.springframework.data.mapping.PersistentPropertyPaths;
@ -118,6 +117,7 @@ public class RelationalEntityWriterUnitTests {
); );
} }
@Test // DATAJDBC-112 @Test // DATAJDBC-112
public void newEntityWithReferenceGetsConvertedToTwoInserts() { public void newEntityWithReferenceGetsConvertedToTwoInserts() {
@ -530,6 +530,51 @@ public class RelationalEntityWriterUnitTests {
); );
} }
@Test // DATAJDBC-417
public void savingANullEmbeddedWithEntity() {
EmbeddedReferenceChainEntity entity = new EmbeddedReferenceChainEntity(null);
// the embedded is null !!!
AggregateChange<EmbeddedReferenceChainEntity> aggregateChange = //
new AggregateChange<>(Kind.SAVE, EmbeddedReferenceChainEntity.class, entity);
converter.write(entity, aggregateChange);
assertThat(aggregateChange.getActions()) //
.extracting(DbAction::getClass, //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn) //
.containsExactly( //
tuple(InsertRoot.class, EmbeddedReferenceChainEntity.class, "", EmbeddedReferenceChainEntity.class, false) //
);
}
@Test // DATAJDBC-417
public void savingInnerNullEmbeddedWithEntity() {
RootWithEmbeddedReferenceChainEntity root = new RootWithEmbeddedReferenceChainEntity(null);
root.other = new EmbeddedReferenceChainEntity(null);
// the embedded is null !!!
AggregateChange<RootWithEmbeddedReferenceChainEntity> aggregateChange = //
new AggregateChange<>(Kind.SAVE, RootWithEmbeddedReferenceChainEntity.class, root);
converter.write(root, aggregateChange);
assertThat(aggregateChange.getActions()) //
.extracting(DbAction::getClass, //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn) //
.containsExactly( //
tuple(InsertRoot.class, RootWithEmbeddedReferenceChainEntity.class, "", RootWithEmbeddedReferenceChainEntity.class, false), //
tuple(Insert.class, EmbeddedReferenceChainEntity.class, "other", EmbeddedReferenceChainEntity.class, true) //
);
}
private CascadingReferenceMiddleElement createMiddleElement(Element first, Element second) { private CascadingReferenceMiddleElement createMiddleElement(Element first, Element second) {
CascadingReferenceMiddleElement middleElement1 = new CascadingReferenceMiddleElement(null); CascadingReferenceMiddleElement middleElement1 = new CascadingReferenceMiddleElement(null);
@ -585,6 +630,19 @@ public class RelationalEntityWriterUnitTests {
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") Element other; @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") Element other;
} }
@RequiredArgsConstructor
static class EmbeddedReferenceChainEntity {
@Id final Long id;
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") ElementReference other;
}
@RequiredArgsConstructor
static class RootWithEmbeddedReferenceChainEntity {
@Id final Long id;
EmbeddedReferenceChainEntity other;
}
@RequiredArgsConstructor @RequiredArgsConstructor
static class ReferenceWoIdEntity { static class ReferenceWoIdEntity {
@ -641,6 +699,11 @@ public class RelationalEntityWriterUnitTests {
@Id final Long id; @Id final Long id;
} }
@RequiredArgsConstructor
private static class ElementReference {
final Element element;
}
@RequiredArgsConstructor @RequiredArgsConstructor
private static class NoIdListMapContainer { private static class NoIdListMapContainer {

Loading…
Cancel
Save