12.2.2 使用注解标注图实体

Neo4j 定义了两种类型的实体:节点(node)和关联关系(relationship)。一般来讲,节点反映了应用中的事物,而关联关系定义了这些事物是如何联系在一起的。

Spring Data Neo4j 提供了多个注解,它们可以应用在模型类型及其域上,实现 Neo4j 中的持久化。表 12.3 描述了这些注解。

注解

描述

@NodeEntity

将 Java 类型声明为节点实体

@RelationshipEntity

将 Java 类型声明为关联关系实体

@StartNode

将某个属性声明为关联关系实体的开始节点

@EndNode

将某个属性声明为关联关系实体的结束节点

@Fetch

将实体的属性声明为立即加载

@GraphId

将某个属性设置为实体的 ID 域(这个域的类型必须是 Long)

@GraphProperty

明确声明某个属性

@GraphTraversal

声明某个属性会自动提供一个 iterable 元素,这个元素是图遍 历所构建的

@Indexed

声明某个属性应该被索引

@Labels

为 @NodeEntity 声明标签

@Query

声明某个属性会自动提供一个 iterable 元素,这个元素是执行给定的 Cypher 查询所构建的

@QueryResult

声明某个 Java 或接口能够持有查询的结果

@RelatedTo

通过某个属性,声明当前的 @NodeEntity 与另外一个 @NodeEntity 之间的关联关系

@RelatedToVia

在 @NodeEntity 上声明某个属性,指定其引用该节点所属的某一个 @RelationshipEntity

@RelationshipType

将某个域声明为关联实体类型

@ResultColumn

在带有 @QueryResult 注解的类型上,将某个属性声明为获取查询结果集中的某个特定列

为了了解如何使用其中的某些注解,我们会将其应用到订单/条目样例中。

在该样例中,数据建模的一种方式就是将订单设定为一个节点,它会与一个或多个条目关联。图 12.2 以图的形式描述了这种模型。

为了将订单指定为节点,我们需要为 Order 类添加 @NodeEntity 注解。如下的程序清单展现了带有 @NodeEntity 注解的 Order 类,它还包含了表 12.3 中的几个其他注解。

程序清单 12.10 为 Order 添加注解,使其成为图数据库中的一个节点
package orders;

import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;

@NodeEntity
public class Order {
	
	@GraphId
	private Long id;
	
	private String customer;
	
	private String type;
	
	@RelatedTo(type="HAS_ITEMS")
	private Set<Item> items = new LinkedHashSet<Item>();

	...	
}

除了类级别上的 @NodeEntity,还要注意 id 属性上使用了 @GraphId 注解。Neo4j 上的所有实体必要要有一个图 ID。这大致类似于 JPA @Entity 以及 MongoDB @Document 类中使用 @Id 注解的属性。在这里,@GraphId 注解标注的属性必须是 Long 类型。

customer 和 type 属性上没有任何注解。只要这些属性不是瞬态的,它们都会成为数据库中节点的属性。

items 属性上使用了 @RelatedTo 注解,这表明 Order 与一个 Item 的 Set 存在关联关系。type 属性实际上就是为关联关系建立了一个文本标记。它可以设置成任意的值,但通常会给定一个易于人类阅读的文本,用来简单描述这个关联关系的特征。稍后,你将会看到如何将这个标记用在查询中,实现跨关联关系的查询。

就 Item 本身来说,下面展现了如何为其添加注解实现图的持久化。

程序清单 12.11 Item 也是图数据库中的节点
package orders;

import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;

@NodeEntity
public class Item {
	
	@GraphId
	private Long id;	
	private Order order;
	private String product;
	private double price;
	private int quantity;
	
	...
}

类似于 Order,Item 也使用了 @NodeEntity 注解,将其标记为一个节点。它同时也有一个 Long 类型的属性,借助 @GraphId 注解将其 标注为节点的图 ID,而 product、price 以及 quantity 属性均会作为图数据库中节点的属性。

Order 和 Item 之间的关联关系很简单,关系本身并不包含任何的数据。因此,@RelatedTo 注解就足以定义关联关系。但是,并不是所有的关联关系都这么简单。

让我们重新考虑该如何为数据建模,从而学习如何使用更为复杂的关联关系。在当前的数据模型中,我们将条目和产品的信息组合到了 Item 类中。但是,当我们重新考虑的时候,会发现订单会与一个或多个产品相关联。订单与产品之间的关系构成了订单的一个条目。图 12.3 描述了另外一种在图中建模数据的方式。

在这个新的模型中,订单中产品的数量是条目中的一个属性,而产品本身是另外一个概念。与前面一样,订单和产品都是节点,而条目是关联关系。因为现在的条目必须要包含一个数量值,关联关系不像前面那么简单。我们需要定义一个类来代表条目,比如如下程序清单所示的 LineItem。

程序清单 12.12 LineItem 类连接了一个 Order 节点和一个 Product 节点
package orders;

import org.springframework.data.neo4j.annotation.EndNode;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.RelationShipEntity;
import org.springframework.data.neo4j.annotation.StartNode;

@RelationShipEntity(type="HAS_LINE_ITEM_FOR")
public class LineItem {
	
	@GraphId
	private Long id;
	
	@StartNode
	private Order order;
	
	@EndNode
	private String product;
	
	private int quantity;
	
	...
}

Order 类通过 @NodeEntity 注解将其标示为一个节点,而 LineItem 类则使用了 @RelationshipEntity 注解。LineItem 同样也有一个 id 属性标注了 @GraphId 注解,不管是节点实体还是关联关系实体,都必须要有一个图 ID,而且其类型必须为 Long。

关联关系实体的特殊之处在于它们连接了两个节点。@StartNode 和 @EndNode 注解用在定义关联关系两端的属性上。在本例中,Order 是开始节点,Product 是结束节点。

最后,LineItem 类有一个 quantity 属性,当关联关系创建的时候,它会持久化到数据库中。

领域对象已经添加了注解,现在就可以保存与读取节点和关联关系了。我们首先看一下如何使用 Spring Data Neo4j 中的 Neo4jTemplate 实现面向模板的数据访问。

Last updated