fix: Update relationship properties objects before populating result entities.

Closes #2904
This commit is contained in:
Michael Simons
2024-05-22 17:21:34 +02:00
parent b38572d3ed
commit 0355a2a8d3
4 changed files with 105 additions and 6 deletions

View File

@@ -179,6 +179,9 @@ public final class MappingSupport {
PersistentPropertyAccessor<Object> relationshipPropertiesAccessor = persistentEntity.getPropertyAccessor(relationshipPropertiesValue);
relationshipPropertiesAccessor.setProperty(persistentEntity.getPersistentProperty(TargetNode.class), newRelationshipObject);
newRelationshipObject = relationshipPropertiesAccessor.getBean();
// If we recreate or manipulate the object including it's accessor, we must update it in the holder as well.
entityHolder.setRelationshipProperties(newRelationshipObject);
}
return newRelationshipObject;
}
@@ -190,14 +193,17 @@ public final class MappingSupport {
*/
@API(status = API.Status.INTERNAL)
public final static class RelationshipPropertiesWithEntityHolder {
private final PersistentPropertyAccessor<?> relationshipPropertiesPropertyAccessor;
private final Object relationshipProperties;
private final Neo4jPersistentEntity<?> relationshipPropertiesEntity;
private PersistentPropertyAccessor<?> relationshipPropertiesPropertyAccessor;
private Object relationshipProperties;
private final Object relatedEntity;
RelationshipPropertiesWithEntityHolder(
Neo4jPersistentEntity<?> relationshipPropertiesEntity,
Object relationshipProperties, Object relatedEntity
) {
this.relationshipPropertiesEntity = relationshipPropertiesEntity;
this.relationshipPropertiesPropertyAccessor = relationshipPropertiesEntity.getPropertyAccessor(relationshipProperties);
this.relationshipProperties = relationshipProperties;
this.relatedEntity = relatedEntity;
@@ -211,6 +217,11 @@ public final class MappingSupport {
return relationshipProperties;
}
private void setRelationshipProperties(Object relationshipProperties) {
this.relationshipProperties = relationshipProperties;
this.relationshipPropertiesPropertyAccessor = relationshipPropertiesEntity.getPropertyAccessor(this.relationshipProperties);
}
public Object getRelatedEntity() {
return relatedEntity;
}
@@ -231,5 +242,12 @@ public final class MappingSupport {
public int hashCode() {
return Objects.hash(relationshipProperties, relatedEntity);
}
@Override
public String toString() {
return "RelationshipPropertiesWithEntityHolder{" +
"relationshipProperties=" + relationshipProperties +
'}';
}
}
}

View File

@@ -44,7 +44,7 @@ public class MovieEntity {
// tag::mapping.relationship.properties[]
@Relationship(type = "ACTED_IN", direction = Direction.INCOMING) // <.>
private List<Roles> actorsAndRoles;
private List<Roles> actorsAndRoles = new ArrayList<>();
// end::mapping.relationship.properties[]
@Relationship(type = "DIRECTED", direction = Direction.INCOMING)

View File

@@ -41,8 +41,21 @@ public class Roles {
this.roles = roles;
}
// end::mapping.relationship.properties[]
public Long getId() {
return id;
}
// tag::mapping.relationship.properties[]
public List<String> getRoles() {
return roles;
}
@Override
public String toString() {
return "Roles{" +
"id=" + id +
'}' + this.hashCode();
}
}
// end::mapping.relationship.properties[]

View File

@@ -23,24 +23,59 @@ import java.util.Collections;
import java.util.Optional;
// end::faq.template-imperative-pt1[]
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.BeforeEach;
// tag::faq.template-imperative-pt1[]
import org.junit.jupiter.api.Test;
// end::faq.template-imperative-pt1[]
import org.neo4j.driver.Driver;
// tag::faq.template-imperative-pt1[]
import org.springframework.beans.factory.annotation.Autowired;
// end::faq.template-imperative-pt1[]
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
// tag::faq.template-imperative-pt1[]
import org.springframework.data.neo4j.core.Neo4jTemplate;
// end::faq.template-imperative-pt1[]
import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
// tag::faq.template-imperative-pt1[]
import org.springframework.data.neo4j.documentation.domain.MovieEntity;
import org.springframework.data.neo4j.documentation.domain.PersonEntity;
import org.springframework.data.neo4j.documentation.domain.Roles;
// end::faq.template-imperative-pt1[]
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.test.BookmarkCapture;
import org.springframework.data.neo4j.test.Neo4jExtension;
import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration;
import org.springframework.data.neo4j.test.Neo4jIntegrationTest;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
// tag::faq.template-imperative-pt1[]
// end::faq.template-imperative-pt1[]
/**
* @author Michael J. Simons
*/
@Disabled
@Neo4jIntegrationTest
// tag::faq.template-imperative-pt2[]
public class TemplateExampleTest {
// end::faq.template-imperative-pt2[]
protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport;
@BeforeEach
void setup(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) {
try (var session = driver.session(bookmarkCapture.createSessionConfig()); var transaction = session.beginTransaction()) {
transaction.run("MATCH (n) detach delete n").consume();
transaction.commit();
bookmarkCapture.seedWith(session.lastBookmarks());
}
}
// tag::faq.template-imperative-pt2[]
@Test
void shouldSaveAndReadEntities(@Autowired Neo4jTemplate neo4jTemplate) {
@@ -53,12 +88,45 @@ public class TemplateExampleTest {
movie.getActorsAndRoles().add(roles1);
movie.getActorsAndRoles().add(roles2);
neo4jTemplate.save(movie);
MovieEntity result = neo4jTemplate.save(movie);
// end::mapping.relationship.properties[]
assertThat(result.getActorsAndRoles()).allSatisfy(relationship -> assertThat(relationship.getId()).isNotNull());
// tag::mapping.relationship.properties[]
Optional<PersonEntity> person = neo4jTemplate.findById("Dean Jones", PersonEntity.class);
assertThat(person).map(PersonEntity::getBorn).hasValue(1931);
assertThat(neo4jTemplate.count(PersonEntity.class)).isEqualTo(2L);
}
// end::faq.template-imperative-pt2[]
@Configuration
@EnableTransactionManagement
@EnableNeo4jRepositories(considerNestedRepositories = true)
static class Config extends Neo4jImperativeTestConfiguration {
@Bean
public Driver driver() {
return neo4jConnectionSupport.getDriver();
}
@Bean
public BookmarkCapture bookmarkCapture() {
return new BookmarkCapture();
}
@Override
public PlatformTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider) {
BookmarkCapture bookmarkCapture = bookmarkCapture();
return new Neo4jTransactionManager(driver, databaseNameProvider, Neo4jBookmarkManager.create(bookmarkCapture));
}
@Override
public boolean isCypher5Compatible() {
return neo4jConnectionSupport.isCypher5SyntaxCompatible();
}
}
// tag::faq.template-imperative-pt2[]
}
// end::faq.template-imperative-pt2[]