Skip to content

Commit

Permalink
fix: Update relationship properties objects before populating result …
Browse files Browse the repository at this point in the history
…entities.

Closes #2904
  • Loading branch information
michael-simons committed May 22, 2024
1 parent a2bb573 commit 0bae3c7
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ public static Object getRelationshipOrRelationshipPropertiesObject(Neo4jMappingC
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;
}
Expand All @@ -190,14 +193,17 @@ private 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;
Expand All @@ -211,6 +217,11 @@ public Object getRelationshipProperties() {
return relationshipProperties;
}

private void setRelationshipProperties(Object relationshipProperties) {
this.relationshipProperties = relationshipProperties;
this.relationshipPropertiesPropertyAccessor = relationshipPropertiesEntity.getPropertyAccessor(this.relationshipProperties);
}

public Object getRelatedEntity() {
return relatedEntity;
}
Expand All @@ -231,5 +242,12 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash(relationshipProperties, relatedEntity);
}

@Override
public String toString() {
return "RelationshipPropertiesWithEntityHolder{" +
"relationshipProperties=" + relationshipProperties +
'}';
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,21 @@ public Roles(PersonEntity person, List<String> 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[]
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,59 @@
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) {

Expand All @@ -53,12 +88,45 @@ void shouldSaveAndReadEntities(@Autowired Neo4jTemplate neo4jTemplate) {
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[]

0 comments on commit 0bae3c7

Please sign in to comment.