Skip to content

Incoming relationships must be set on both sides to actually persist #2264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jposthauer opened this issue May 26, 2021 · 6 comments
Closed
Assignees

Comments

@jposthauer
Copy link

With the given setup, the test only passes if I have both actor.movies.add(movie) AND movie.actors.add(actor). I would expect that actor.movies.add(movie) would be sufficient.

@Node
public class Actor {
    @Relationship(type = "ACTED_IN")
    private List<Movie> movies;
}

@Node
public class Movie {
     @Relationship(type = "ACTED_IN", direction = Relationship.Direction.INCOMING)
     private List<Actor> actors = new ArrayList<>();
}


@Query("MATCH (actor:Actor {id: $actorId}) "
    + "OPTIONAL MATCH (actor)-[acted_in:ACTED_IN]->(movie:Movie)"
    + "RETURN actor, COLLECT(acted_in), COLLECT(movie);")
Optional<Actor> findByIdWithMovies(String actorId);


@Test
fun findByIdWithMovies() {
    val actor = Actor()
    val movie = Movie()

    actor.movies.add(movie)
    movie.actors.add(actor)
    actorRepository.save(actor)

    val consumed = actorRepository.findByIdWithMovies(actor.id).get()
    assertThat(consumed.movies).isNotEmpty
}
@meistermeier
Copy link
Collaborator

Thanks for reporting this. Can you please provide the Spring Data Neo4j version you are using?

@meistermeier meistermeier added blocked: awaiting feedback and removed status: waiting-for-triage An issue we've not yet triaged labels May 26, 2021
@jposthauer
Copy link
Author

Spring Boot Version: 2.4.5
Spring Data Neo4j Version: 6.0.8

@meistermeier
Copy link
Collaborator

After a short period thinking about this, I think that there is nothing we can do about the initial problem you have.
First of all the Movie would need to get the Actor added during the save to reflect the truth that got persisted in the database.
This started our though process: If there would be another Actor on the Movie, which entity tells the truth upfront the save?
More drastically: What if the Actor and Movie from you example above were loaded from the database and you want to remove the relationship again. Staying with the approach you gave initially would mean just to remove it from the Actor. But then there is still an Actor referenced from the Movie.
You see, it is not easy to solve this without adding the objects in each other's collections and with that have a unambiguous model.
I will keep this issue open to comment and to move the focus for me towards more stability when it comes to such scenarios. While I am writing this, I came to the conclusion that the other way (setting the actor in the movie) might already / still work.
The logic is:

  1. Save the Actor
  2. From Actor -> Movie: Delete/Create relationships and process the related Movies
  3. From Movie -> Actor: Delete/Create relationships and process all related Actors
    Since the actors list in 3. wouldn't be empty, this might lead to inconsistent data.

@meistermeier
Copy link
Collaborator

Thought again about this and came to the conclusion that my plan, to break the current implementation with my assumption above, won't work (and consequentially not break anything).
This is because storing (a:Actor)-[r]-(:Movie)-[]-(a) does not even go the path to the movie if there is no r.
As a result a assigned Actor on the Movie cannot get persisted at all.
I hope my explanation above and this makes things clear, why you would have to store both sides, if you really want to have a bidirectional model.
If you have any questions about this or comments, I leave the issue open for a few days.

@jposthauer
Copy link
Author

That does make sense, thank you for the great explanation!

@meistermeier
Copy link
Collaborator

Glad it helped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants