Sto riscontrando un comportamento strano quando cerco entità nodo con Spring Data Neo4j (SDN). Se utilizzo GraphRepository.findOne (long) restituirà un'entità con quell'identificatore anche se l'entità non è dello stesso tipo.Risoluzione di entità con Spring Data Neo4j restituisce tipi di entità errati
Questo è ciò che la mia struttura entità (molto) assomiglia semplificato: repository
@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;
}
Per ogni tipo di entità, che ho creato come questo:
@Repository
public interface PersonRepository extends GraphRepository<Person> {}
@Repository
public interface AuditRepository extends GraphRepository<Audit> {}
Ho un abstract classe base per le mie classi del livello di servizio. Questo è ciò che grosso modo simile: Quando eseguo il seguente codice, il risultato non è come previsto
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;
}
}
:
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);
Ci si aspetterebbe che l'AuditRepository sarebbe tornato nulla, ma questo in non è il caso. Invece, restituisce un Audit con identificatore 1L e null in tutte le sue proprietà. Sembra che finché c'è un nodo che corrisponde a un determinato identificatore, verrà restituito, non importa quale sia il suo tipo. Se Person e Audit avessero nomi di proprietà corrispondenti, anch'essi conterrebbero anche i loro valori ... Tutto questo comportamento previsto o mi manca qualcosa?
Per ora, ho risolto questo problema con il codice riportato di seguito, in cui eseguo personalmente il controllo di tipo.
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];
}
}
Se è necessaria più configurazione, per favore fatemelo sapere.
mie versioni framework sono:
<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>
grazie @tstorms, questo post e la soluzione sono stati molto utili per me quando ho avuto a che fare con questo bug. – Hendrik
Solo una breve domanda: l'annotazione '@ Autowired' di 'PersonServiceImpl' si trova nel campo' PersonRepository' piuttosto che nel costruttore? – tigerjack89
No, perché? Ho scelto l'iniezione del costruttore invece dell'iniezione sul campo. Una lettura molto interessante sul perché l'iniezione sul campo può essere "cattiva": http://olivergierke.de/2013/11/why-field-injection-is-evil/. – tstorms