Ich habe merkwürdiges Verhalten, wenn ich mit Spring Data Neo4j (SDN) nach Knotenentitäten suche. Wenn ich GraphRepository.findOne (long) verwende, gibt es eine Entität mit dieser ID zurück, obwohl die Entität nicht vom selben Typ ist. DieseAuflösen von Entitäten mit Spring Data Neo4j gibt falsche Entitätstypen zurück
ist, was meine (sehr) vereinfachte Einheit Struktur wie folgt aussieht:
@NodeEntity
protected abstract class BaseEntity {
@GraphId
private Long id;
@JsonIgnore
@RelatedTo(type = RelationType.ENTITY_AUDIT)
private Audit audit;
}
@NodeEntity
public final class Person extends BaseEntity {
@Indexed(indexType = IndexType.FULLTEXT)
private String firstName;
@Indexed(indexType = IndexType.FULLTEXT)
private String lastName;
}
@NodeEntity
public class Audit extends BaseEntity {
@RelatedTo(type = RelationType.ENTITY_AUDIT, direction = Direction.INCOMING)
private BaseEntity parent;
private Long date;
private String user;
}
Für jeden Entitätstyp, ich habe wie diese erstellt Repositories:
@Repository
public interface PersonRepository extends GraphRepository<Person> {}
@Repository
public interface AuditRepository extends GraphRepository<Audit> {}
ich eine abstrakte habe Basisklasse für meine Service-Layer-Klassen. Das ist, was sie wie grob aussehen:
public abstract class MyServiceImpl<T extends BaseEntity> implements MyService<T> {
private GraphRepository<T> repository;
public MyServiceImpl(final GraphRepository<T> repository) {
this.repository = repository;
}
@Override
public T read(final Long identifier) throws EntityNotFoundException {
return repository.findOne(identifier);
}
@Override
public T create(final T entity) {
return repository.save(entity);
}
}
@Service
public class PersonServiceImpl extends MyServiceImpl<Person> implements PersonService {
private PersonRepository personRepository;
@Autowired
public PersonServiceImpl(final PersonRepository personRepository) {
super(personRepository);
this.personRepository = personRepository;
}
}
Wenn ich den folgenden Code ausführen, wird das Ergebnis nicht wie erwartet:
Person person = new Person();
person.setFirstName("Test");
person.setLastName("Person");
personService.create(person);
// suppose the person identifier is 1L
final Audit audit = auditRepository.findOne(1L);
Sie würden erwarten, dass die AuditRepository null zurückkommen würde, aber dies in nicht der Fall. Stattdessen gibt es ein Audit mit dem Bezeichner 1L und null in allen seinen Eigenschaften zurück. Solange es einen Knoten gibt, der einem gegebenen Bezeichner entspricht, wird er zurückgegeben, ohne dass er seinen Typ angibt. Wenn Person und Audit übereinstimmende Eigenschaftsnamen hätten, würden sie auch ihre Werte enthalten ... Ist all das erwartete Verhalten, oder fehle ich etwas?
Für jetzt habe ich dieses Problem mit dem Code unten gelöst, wo ich die Typüberprüfung selbst mache.
public abstract class MyServiceImpl<T extends BaseEntity> implements MyService<T> {
private GraphRepository<T> repository;
public MyServiceImpl(final GraphRepository<T> repository) {
this.repository = repository;
}
@Override
public T read(final Long identifier) throws EntityNotFoundException {
return get(identifier);
}
protected T get(final Long identifier) throws EntityNotFoundException {
final T entity = repository.findOne(identifier);
final Class<T> type = getServiceType();
if (entity == null || !(type.equals(repository.getStoredJavaType(entity)))) {
throw new EntityNotFoundException(type, identifier);
}
return entity;
}
@SuppressWarnings("unchecked")
private Class<T> getServiceType() {
return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
}
Wenn Sie mehr Konfiguration benötigen, lassen Sie es mich bitte wissen.
Meine Framework-Versionen sind:
<spring.version>3.2.0.RC1</spring.version>
<neo4j.version>1.8</neo4j.version>
<spring.data.neo4j.version>2.1.0.RELEASE</spring.data.neo4j.version>
danke @tstorms, dieser Beitrag und Ihre Problemumgehung waren sehr hilfreich für mich, wenn Sie mit diesem Fehler zu tun haben. – Hendrik
Nur eine kurze Frage: Sollte die Annotation "@ Autowired" von "PersonServiceImpl" auf dem Feld "PersonRepository" statt auf dem Konstruktor stehen? – tigerjack89
Nein, warum? Ich habe die Konstruktorinjektion anstelle der Feldinjektion gewählt. Eine sehr interessante Lektüre darüber, warum Feldinjektion "böse" sein kann: http://olivergierke.de/2013/11/why-field-injection-is-evil/. – tstorms