spring-data-neo4j icon indicating copy to clipboard operation
spring-data-neo4j copied to clipboard

Cannot query fields defined as types of base classes

Open sunny-chung opened this issue 3 years ago • 2 comments

------------ Basic Info ------------

Spring Data Neo4j Version: 6.3.0 Neo4j Database Version: 4.4.5 JVM Version: 11.0.12

Sample Project: https://github.com/sunny-chung/movies-java-spring-data-neo4j-6-bug-demo

------------ Description ------------

After migrating to SDN 6, entity classes defined as fields with type of base classes cannot be queried.

For example, in the sample project, part of the Person class is extracted to a base class named Base, and the type of the field directors in the Movie node entity is changed from List<Person> to List<Base>. In particular, the field name is extracted from the class Person to the classBase, and directors is a field annotated with @Relationship under the class Movie. Afterwards, following issues are observed:

  1. With a custom query, directors cannot be queried and is always null, although there exists matched Person data.
	@Query("MATCH (n:`Movie`)<-[r_0:`DIRECTED`]-(m_0:`Person`) " +
			"MATCH (n)<-[r1:`ACTED_IN`]-(m1:`Person`) " +
			"WHERE m_0.name = $name RETURN n, COLLECT(r1), COLLECT(m1), COLLECT(r_0), COLLECT(m_0)")
	List<Movie> findAllByDirectorsName2(String name);
  1. Following query always returns empty list.
	List<Movie> findAllByDirectorsName(String name);

For easy reference, entity definitions are copied to here.

@Node
public class Movie {

	@Id
	private final String title;

	@Property("tagline")
	private final String description;

	@Relationship(type = "ACTED_IN", direction = Direction.INCOMING)
	private List<Actor> actors = new ArrayList<>();

	@Relationship(type = "DIRECTED", direction = Direction.INCOMING)
	private List<Base> directors = new ArrayList<>();

	private Integer released;

	public Movie(String title, String description) {
		this.title = title;
		this.description = description;
	}

	// ... public getters & setter ...
}
@Node
public class Person extends Base {

	private Integer born;

	public Person(Integer born, String name) {
		super(name);
		this.born = born;
	}

	// ...
}
public abstract class Base {

    @Id
    private final String name;

    private Integer version = 0;

    public Base(String name) {
        this.name = name;
    }

    // ...
}

sunny-chung avatar May 21 '22 10:05 sunny-chung

Thanks for reporting this. At the moment there is no concept in SDN to support non-entity parent classes in the mapping declaration. There are basically two solutions to this:

  1. You have to add the @Node to the base class and to as a label to the node in the database.
  2. You stick with the concrete definition of a Person in the Movie entity that is still a child of the Base class. In this case no annotations and change of the data is needed.

We will for sure have a look the next days, if this is something we might could bring into SDN without breaking any existing functionality.

meistermeier avatar Jun 10 '22 19:06 meistermeier

Update on this one: I investigated this a little bit more. Outcome is that for now we have to stick with the two options above. The reason is that we register eligible nodes although they are not explicitly annotated with @Node if they have at least an @Id field (no matter if abstract or not). This means that the generated query starting with MATCH (movie:Movie)<-[r_0:DIRECTED]-(m_0:Base) WHERE m_0.name = $name ... is correct but obviously does not match the node. At the custom query side, the mapping of the directors does not happen because it also expects nodes with the label Base to be present. Currently trying an approach where we treat non-annotated (abstract) base classes different for reading purposes. I mention reading explicitly here because a write does only add the label of the concrete class. So this would evolve this somehow[1] into a bug because you cannot read what you have written.

[1] it's still an edgy case from my point of view and I would really fix it for reading. But TBH I expected the additional Base label to get applied on write.

meistermeier avatar Jun 15 '22 15:06 meistermeier

Closing this, because we have a workaround and cannot fix the situation without introducing another problem. If you have the feeling that it could be solved in another way in SDN, please re-open it.

meistermeier avatar Jan 20 '23 12:01 meistermeier