Spring Data Neo4j(二)

什么是SDN

Spring Data Neo4j 简称SND,是一个对象-图形映射(OGM)框架,是为了简化开发者的工作而创建的,它的目的是通过处理所有底层工作和从Neo4j读域实体并写回去所必须的映射逻辑来提高效率

SND从很大程度上为开发者提供了方便的使用代码和库函数,能非常方便的集成与Spring,但是SDN不适合一次处理任意类型的大量数据的场景,要加载或者存储的任何逻辑在一次操作中超过10000个单元对SDN来说不是一个很好的选择。SDN相当于充当了一个间接层的,操作数量过大的话,相比原生的核心API会慢很多。

SDN建模

假设现在有两个节点 流程(Process) and 任务(Task) 通过关系(PROCESS_IN)建立两个节点的连接,应当如何建模?

分析在工作流程业务中,** 流程(Process)实例** 与** 任务(Task)实例** 是一对多的关系,一个任务只能有一个流程,一个流程包含多个任务。

在SDN中,节点、关系 都可以用过注解来表示,非常方便

** @NodeEntity** 增加该注解属性在类上,表示这是一个节点。
** @GraphId ** 该节点的唯一编号,会自动生成,跟mysql、oracle里面的id一个性质,是必须的。
** @Relationship(type = "")** 该属性增加在节点的属性上,该属性必须为节点,type 表示连接他们的关系(Relationship)的名字。
** @RelationshipEntity(type = "") ** 该注解增加在类上,表示他是一个关系(Relationship) type表示该关系的名字,不写则默认类的名字。
** @StartNode ** 该属性增加在关系的属性上,该属性必须为节点 表示该节点为起点节点。
** @EndNode** 该属性增加在关系的属性上,该属性必须为节点 表示该节点为结束节点。
注意: 节点与节点的关系表述,必须要有明确的 开始和结束

如下图所示:

SDN访问和持久化实体

SDN 提供了一个 Neo4jTemplate 类,能用于实例化,可以直接使用或当 Spring 初始化时用于应用程序。类似于Spring模板类JDBCTemplate,它提供了很多其他的底层应用方法用于操作、查询以及获得对节点和关系的访问。

@Autowired private Neo4jTemplate neo4jTemplate; @Transactional public void saveTask(){ Task task = new Task(); task.setTaskName("测试任务"); Task save = neo4jTemplate.save(task); Task load = neo4jTemplate.load(Task.class, save.getId()); System.out.println(load.getTaskName());

如上述表示,通过 @Autowired 注入该类,就可以调用起操作、查询等方法,实现对数据的实例化。但是一般在的真正的业务代码的实现中,用于加载和保存实体一般是通过资源库模式来实现(简单来说,就是用一个知道如何翻译域实体到或从数据仓库格式替换合适的资源库实现)。
SDN 资源库在某一段时间是专门设置用于一个域类,并针对对应的域类提供整个范围的默认操作。
SDN 提供了 Interface GraphRepository<T> 接口,自己定义的接口继承扩展 GraphRepository ,它定义了域类可用的默认操作的最广集合。Java泛型的使用把他与对应的域实体联系起来。

  public interface TaskRepository extends GraphRepository<Task> {}

GraphRepository接口从实质上巩固的所有的其他接口,因此为Task定义了包括CRUD的操作、索引和遍历。该接口比Neo4jTemplate 类高一级,它也是提供许多样板代码的实现,但以更针对域的方式。

SDN注解查询

SDN除了提供了一系列的接口查询外,还提供了更高级的注解查询,使用注解@Query用于标识一个执行的查询。注解可以用于一个节点的实体的一个字段上,或者知识库接口中的方法上。当一个节点实体上的字段被访问或在一个知识库接口上调用一个方式时,查询被执行并且返回结果。

@Query注释可以定义在你自己实现的特定的接口上,下面定义了两个接口 一个通过名字查询任务,一个则是通过流程实例id查询相关的任务。查询可设置变量,顺序默认为接口参数名字。

@Repository
public interface TaskRepository extends GraphRepository<Task> {
    @Query("MATCH (t:Task) WHERE t.taskName =~ ('(?i).*'+{taskName}+'.*') RETURN t")
    Collection<Task> findByNameContaining(@Param("taskName") String taskName);
    @Query("START p = node({id}) MATCH (p:Process)-[r:PROCESS_IN]->(t:Task) RETURN t;")
    Collection<Task> findByProcessId(@Param("id") Long id);

SDN也能理解相关的属性定义,如果你想通过任务的名字查询某个任务,可以定义以下方法。这里应用了属性的第一部分,如果这个属性是基于这个任务类型的,就可以通过任务的名字进行搜索。但属性必须是存在的,不存在启动会出错。

@Repository
public interface TaskRepository extends GraphRepository<Task> {
    Task findByTaskName(@Param("taskName") String taskName);

如果你想有多个属性并列查询时,你可以通过And 或者Or将两个属性联系起来,查询,参数则按顺序写入。

@Repository
public interface TaskRepository extends GraphRepository<Task> {