【问题标题】:Creating unique path in Neo4J using Cypher and SDN @Query annotation使用 Cypher 和 SDN @Query 注解在 Neo4J 中创建唯一路径
【发布时间】:2014-12-01 01:23:00
【问题描述】:

我想使用 Spring-Data Neo4j 在 Neo4j 中对包含公司及其业务关系的图表进行建模。所以我为公司创建了节点,为业务关系创建了边缘。然而,有一堆不同类型的关系(买方、供应商、制造商等和一个通用版本“DOES_BUSINESS_WITH”)。每个关系都有一个属性,即目标公司的源公司的内部 ID,例如采购员对每个供应商都有一个内部 ID。并且每一对公司在每个方向上都可以有一个类型的关系。

我的设置方式是为公司设置一个@NodeEntity,为每个不同的业务关系设置一个@RelationshipEntity。由于所有这些关系都具有相同的属性,它们都扩展了泛型类并简单地将正确的标签添加到边缘:

@RelationshipEntity(type="DOES_BUSINESS_WITH")
public class BusinessRelation  {
    @GraphId
    private Long id;

    @Fetch
    @StartNode
    private Company from;

    @Fetch
    @EndNode
    private Company to;

    @Indexed
    private String knownAsId;

    // getters and setters omitted

}

@RelationshipEntity(type="SUPPLIER")
public class SupplierRelation extends BusinessRelation {

    public SupplierRelation() {
    }
}

由于我有很多不同的关系,我想使用一个存储库接口来处理所有这些。

现在,当我获得关系时,我想在(已经存在的)公司之间建立新的关系,或者在必要时修改现有的关系。所以我决定像这样使用 CREATE UNIQUE 密码子句:

public interface BusinessRelationRepository extends GraphRepository<BusinessRelation> {
     @Query(value="match (source:Company {orgId:{0}}),(target:Company {orgId:{1}}) create unique (source)-[r:SUPPLIER]->(target) return r", elementClass=SupplierRelation.class)
    SupplierRelation createSupplierMarker(String sourceOrgId, String targetOrgId);
    // ...
}

不幸的是,这引发了异常:

org.springframework.dao.DataRetrievalFailureException: No such property, '__type__'.; nested exception is org.neo4j.graphdb.NotFoundException: No such property, '__type__'.
    at org.springframework.data.neo4j.support.Neo4jExceptionTranslator.translateExceptionIfPossible(Neo4jExceptionTranslator.java:66)
    at org.springframework.data.neo4j.support.Neo4jTemplate.translateExceptionIfPossible(Neo4jTemplate.java:448)
    at org.springframework.data.neo4j.support.Neo4jTemplate.doExecute(Neo4jTemplate.java:459)
    at org.springframework.data.neo4j.support.Neo4jTemplate.access$000(Neo4jTemplate.java:87)
    at org.springframework.data.neo4j.support.Neo4jTemplate$2.doInTransaction(Neo4jTemplate.java:471)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
    at org.springframework.data.neo4j.support.Neo4jTemplate.exec(Neo4jTemplate.java:468)
    at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.execute(GraphRepositoryQuery.java:82)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:421)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:381)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy65.createSupplierMarker(Unknown Source)

我希望将 elementClass 属性添加到 @Query 注释可以为 SDN 提供足够的信息以将结果映射回所需的 SupplierRelation,但它没有。它实际上没有任何效果。

我可以通过自己将 __type__ 属性添加到 Cypher 查询来解决该问题,但是我的代码对 Spring Data Neo4j 的内部工作原理的了解比我想要的要多。所以这行得通:

@Query(value="match (source:Company {orgId:{0}}),(target:Company {orgId:{1}}) create unique (source)-[r:SUPPLIER {__type__:\"SupplierRelation\"}]->(target) return r")
SupplierRelation createSupplierMarker(String sourceOrgId, String targetOrgId);

有没有更好的解决方案不需要我在代码中设置 __type__ 属性?

【问题讨论】:

    标签: spring neo4j cypher spring-data-neo4j


    【解决方案1】:

    Volker,你是对的,默认的类型表示策略在这里有点过度约束。

    实际上我们想添加一个仅使用 rel 类型映射到 SDN 的关系 TRS,但我还没有实现。

    您也可以将您的属性添加为

    @Indexed(unique=true) private String knownAsId;
    

    然后构造这些关系实体实例之一并使用

    template.save(relation);
    

    这应该也可以。

    【讨论】:

    • 谢谢,迈克尔。不幸的是,我的流程并不能保证我总是拥有 knownAsId。我很有可能在不知道源公司对目标公司的内部 ID 的情况下推导出这两家公司之间的关系。并在稍后的阶段找出该 ID 是什么。
    • 在我的逻辑中,如果关系不存在,我想创建关系,如果存在则更新属性。走 CREATE UNIQUE 路线似乎是最简单的,因为我所要做的就是更新属性。此外,我不必查找两端的节点来创建关系,我只需要组织 ID(不是 @GraphIds,而是 Company 节点的属性)。
    猜你喜欢
    • 1970-01-01
    • 2017-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多