Query creation

本章介绍使用 SDN 的抽象层时进行查询的技术创建。这里会有所简化,因为我们并未讨论每种可能的情况,而是坚持其背后的理念。

Save

除了 find/load 操作外,save 操作在处理数据时也是使用最频繁的操作之一。通常,save 操作调用会向数据库发送多条语句,以确保生成的图形模型与给定的 Java 模型相匹配。

  1. 将创建一个联合语句来创建节点(如果找不到节点的标识符),或在节点自身存在时更新节点的属性。(OPTIONAL MATCH (hlp:Person) WHERE id(hlp) = $id WITH hlp WHERE hlp IS NULL CREATE (n:Person) SET n = $properties RETURN id(n) UNION MATCH (n) WHERE id(n) = $id SET n = $properties RETURN id(n))

  2. 如果实体是 not 新实体,将在数据库中删除在域模型中第一个找到类型的实体的所有关系。(MATCH (startNode)-[rel:Has]→(:Hobby) WHERE id(startNode) = $fromId DELETE rel)

  3. 相关实体的创建方式与根实体相同。(OPTIONAL MATCH (hlp:Hobby) WHERE id(hlp) = $id WITH hlp WHERE hlp IS NULL CREATE (n:Hobby) SET n = $properties RETURN id(n) UNION MATCH (n) WHERE id(n) = $id SET n = $properties RETURN id(n))

  4. 将创建关系本身。(MATCH (startNode) WHERE id(startNode) = $fromId MATCH (endNode) WHERE id(endNode) = 631 MERGE (startNode)-[:Has]→(endNode))

  5. 如果相关实体还与其他实体有关,将启动与 2 中相同的过程。

  6. 从根实体上的下一个定义的关系开始 2.,但将 first 替换为 next

正如您所见,SDN 尽最大努力使您的图形模型与 Java 世界保持同步。这是我们强烈建议您不要加载、操作和保存子图形的原因之一,因为这可能会导致从数据库中删除关系。

Multiple entities

save 操作被重载,增加了接受多个同类型实体的功能。如果你使用生成的 ID 值或利用乐观锁,每个实体都会导致单独的 CREATE 调用。

在其他情况下,SDN 将使用实体信息创建一个参数列表,并用 MERGE 调用提供该列表。

UNWIND $entities AS entity MERGE (n:Person {customId: entity.$id}) SET n = entity.properties RETURN collect(n.customId) AS $ids

参数如下所示:

:params {entities: [{id: 'aa', properties: {name: "PersonName", theId: "aa"}}, {id 'bb', properties: {name: "AnotherPersonName", theId: "bb"}}]}

Load

load 文档不仅会显示查询的 MATCH 部分是什么样的,还会显示数据是如何返回的。

最简单的加载操作是 findById 调用。它将匹配你查询的类型标签的所有节点,并对 ID 值进行筛选。

MATCH (n:Person) WHERE id(n) = 1364

如果提供自定义 ID,SDN 将使用你定义为 ID 的属性。

MATCH (n:Person) WHERE n.customId = 'anId'

要返回的数据被定义为 map projection

RETURN n{.first_name, .personNumber, internalNeo4jId: id(n), nodeLabels: labels(n)}

如你所见,其中有两个特殊字段:internalNeo4jIdnodeLabels。当把数据映射到 Java 对象时,这两个字段至关重要。internalNeo4jId 的值可能是 id(n) 或提供的自定义 ID,但在映射过程中必须存在一个已知的字段可以引用。nodeLabels 可以确保此节点上的所有已定义标签都可寻址并被映射。当使用继承时需要这样做,而你查询的不是具体类或者已经定义了只定义超类型的关系。

关于关系的讨论:如果您在实体中定义了关系,它们将作为 pattern comprehensions 添加到返回的地图中。然后,上述返回部分将如下所示:

RETURN n{.first_name, …​, Person_Has_Hobby: [(n)-[:Has]→(n_hobbies:Hobby)|n_hobbies{internalNeo4jId: id(n_hobbies), .name, nodeLabels: labels(n_hobbies)}]}

SDN 使用的地图投影和模式理解可确保只查询你已定义的属性和关系。

如果你有自引用节点,或者创建的架构有可能导致返回的数据中形成循环,SDN 将使用级联/数据驱动查询创建。它将以最初的查询开始,查询特定节点,然后考虑条件,逐步遍历结果节点,如果它们的关联也被映射,则会动态创建进一步的查询。此查询创建和执行循环将一直持续,直到没有查询找到新的关系或节点为止。创建方式可以类比于保存/更新过程。