查询创建
本章内容涉及在使用SDN抽象层时查询的技术创建方法。由于我们不会讨论所有可能的情况,因此会做一定程度的简化,仅围绕其核心理念展开。
保存
除了 find/load 操作外,save 操作是在处理数据时最常使用的操作之一。通常情况下,保存操作调用会向数据库发出多个语句,以确保生成的图模型与给定的 Java 模型相匹配。
-
联合语句将被创建,该语句要么创建一个节点(如果无法找到节点的标识符),要么更新已存在节点的属性。
(
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)) -
如果该实体不是新的,则将从数据库中移除领域模型中第一个找到的该类型的所有关系。
(
MATCH (startNode)-[rel:Has]→(:Hobby) WHERE id(startNode) = $fromId DELETE rel) -
相关实体将按照与根实体相同的方式创建。
(
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)) -
关系本身将被创建
(
MATCH (startNode) WHERE id(startNode) = $fromId MATCH (endNode) WHERE id(endNode) = 631 MERGE (startNode)-[:Has]→(endNode)) -
如果相关实体也与其他实体存在关联,则将启动与步骤2中相同的流程。
-
对于根实体上定义的下一个关系,从2开始,但将 first 替换为 next。
| 如您所见,SDN 尽最大努力保持您的图模型与 Java 世界同步。这是为什么我们强烈建议您不要加载、操作和保存子图的原因之一,因为这可能导致关系从数据库中被移除。 |
多个实体
操作 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 不仅会向您展示查询中 MATCH 部分的结构,还会说明数据是如何返回的。
最简单的加载操作是 findById 调用。它会匹配所有具有您所查询类型的标签的节点,并对 id 值进行过滤。
MATCH (n:Person) WHERE id(n) = 1364
如果提供了自定义ID,SDN将使用您定义的属性作为ID。
MATCH (n:Person) WHERE n.customId = 'anId'
要返回的数据被定义为一个 地图投影。
RETURN n{.first_name, .personNumber, __internalNeo4jId__: id(n), __nodeLabels__: labels(n)}
如您所见,其中包含两个特殊字段: __internalNeo4jId__ 和 __nodeLabels__。在将数据映射到 Java 对象时,这两个字段都至关重要。 __internalNeo4jId__ 的值要么是 id(n),要么是所提供的自定义 ID,但在映射过程中,必须存在一个已知的字段以供引用。 __nodeLabels__ 确保此节点上定义的所有标签均可被找到并完成映射。这在使用继承且查询非具体类,或关系仅定义了超类型的情况下尤为必要。
关于关系:如果您在实体中定义了关系,它们将作为模式匹配被添加到返回的映射中。上述返回部分随后将如下所示:
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 会回退到级联/数据驱动的查询生成方式。初始查询从查找特定节点并结合相关条件开始,随后遍历结果节点;如果这些节点的关系也被映射,则会即时创建进一步的查询。该查询生成与执行循环将持续进行,直到没有新的关系或节点被查找到为止。这种查询生成方式可类比于保存/更新过程。