使用Spring Data Neo4j解析实体会返回错误的实体类型

tst*_*rms 5 spring neo4j nosql spring-data-neo4j

当我使用Spring Data Neo4j(SDN)查找节点实体时,我遇到了一些奇怪的行为.如果我使用GraphRepository.findOne(long),它将返回具有该标识符的实体,即使该实体的类型不同.

这就是我(非常)简化的实体结构:

@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;

}
Run Code Online (Sandbox Code Playgroud)

对于每种实体类型,我都创建了这样的存储库:

@Repository
public interface PersonRepository extends GraphRepository<Person> {}

@Repository
public interface AuditRepository extends GraphRepository<Audit> {}
Run Code Online (Sandbox Code Playgroud)

我的服务层类有一个抽象基类.这就是他们大致的样子:

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

当我执行以下代码时,结果不符合预期:

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);
Run Code Online (Sandbox Code Playgroud)

您希望AuditRepository将返回null,但事实并非如此.相反,它返回一个标识为1L的Audit,并在其所有属性中返回null.似乎只要有一个节点对应于给定的标识符,它就会返回,不管它的类型是什么.如果Person和Audit有匹配的属性名称,那么它们也会包含它们的值...是所有这些预期的行为,还是我错过了什么?

现在,我已经用下面的代码解决了这个问题,我自己进行了类型检查.

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];
    }

}
Run Code Online (Sandbox Code Playgroud)

如果您需要更多配置,请告诉我.

我的框架版本是:

<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>
Run Code Online (Sandbox Code Playgroud)

Mic*_*ger 2

我们之前有过这种行为,但它因返回错误的实体类型而失败,我们更改了该行为,以便使用您提供的类型自动将节点投影到。

public <S extends PropertyContainer, T> T createEntityFromStoredType(S state, MappingPolicy mappingPolicy) {..}
Run Code Online (Sandbox Code Playgroud)

模板。createEntityFromStoredType(node, null) 将为您获取具有存储状态的对象。

public Class getStoredJavaType(Object entity) {} 
Run Code Online (Sandbox Code Playgroud)

为您提供节点或关系(或实体)的存储类

我们讨论了如何改变行为,尤其是失败。在存储库中。

问题是,接下来会发生什么?例外吗?结果为空?...

一般来说,如果您提供有效的原始节点 ID,则返回错误或 Null 似乎也不像正确答案?

  • 我想在这里权衡一下:在存储库级别上,我觉得如果没有 id 为 123L 的人,那么 PersonRepository.find(123L) 返回任何内容都是不可接受的。我觉得唯一正确的行为是抛出 ObjectNotFoundException。我还觉得当前的行为非常隐含并且没有很好的记录,这反过来又导致我在代码中引入了错误。 (7认同)