2012-11-13 4 views
5

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> 
+0

danke @tstorms, dieser Beitrag und Ihre Problemumgehung waren sehr hilfreich für mich, wenn Sie mit diesem Fehler zu tun haben. – Hendrik

+0

Nur eine kurze Frage: Sollte die Annotation "@ Autowired" von "PersonServiceImpl" auf dem Feld "PersonRepository" statt auf dem Konstruktor stehen? – tigerjack89

+0

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

Antwort

2

wir dieses Verhalten hatten vor, dass sie auf dem falschen Entitätstyp zurückgegeben ausgefallen ist, wir dieses Verhalten geändert, so dass die Art Sie wird liefern verwendet, um den Knoten automatisch zu einem Projekt .

public <S extends PropertyContainer, T> T createEntityFromStoredType(S state, MappingPolicy mappingPolicy) {..} 

Vorlage. createEntityFromStoredType (node, null) ruft das Objekt mit dem gespeicherten Status ab.

public Class getStoredJavaType(Object entity) {} 

gibt Ihnen die gespeicherten Klasse für einen Knoten oder Beziehung (oder Einrichtung)

Wir hatten eine Diskussion über das Verhalten wieder zu ändern und esp scheitern. in Repositories.

Die Frage ist, was soll dann passieren? Eine Ausnahme? Ein Null-Ergebnis? ...

Im Allgemeinen, wenn Sie eine rohe Knoten-ID angeben, die gültig ist, scheint die Rückgabe eines Fehlers oder Null auch keine richtige Antwort zu sein?

+0

In meiner Problemumgehung gebe ich eine Ausnahme aus, wenn eine Entität eines falschen Typs zurückgegeben wird. Für mich fühlt sich das natürlich an. Vielleicht ist es nur eine Frage des Geschmacks? Obwohl das Ändern des Verhaltens ideal für mein Projekt wäre, würde das nicht viele Produktionsumgebungen zerstören? – tstorms

+0

Ich würde zustimmen, dass eine Ausnahme ausgelöst werden sollte, wenn ein Knoten mit der ID gefunden wird, aber es ist nicht vom Typ ausgenommen. Warum ist das? Ich verwende Anmerkungen zu Eigenschaften des erwarteten Typs. Eine Ausnahme wird ausgelöst, da erwartete Eigenschaften beim Initialisieren des Objekts nicht gefunden werden. Eine Ausnahme vom Repository wäre in diesem Fall IMHO sauberer. – spa

+1

Um die meisten Anwendungsszenarien zu erfüllen: Vielleicht sollte das gewünschte Verhalten konfigurierbar sein. – spa