使用Spring Data Neo4j进行领域建模

大家好,威利在这里。 上次我告诉您,我正在使用Neo4j和Spring Data Neo4j构建Skybase CMDB,我很高兴收到很多对此的积极反馈。 我展示了一些代码,但没有那么多。 在本文中,我将向您展示如何使用Spring Data Neo4j在Skybase中构建人员配置项 (CI)。

人CI要求

我们将在这里简单地通过构建人员CI来开始。 出于各种原因而使人们进入CMDB很有用:它们使您可以定义细粒度的访问控制(例如,Jim可以将这样的应用程序部署到开发环境中; Eric可以将他想要的任何东西部署到他想要的任何地方;等等。 ); 它们使您可以定义将接收关键事件通知的组。 等等

我们的个人CI将有一个用户名,名字和姓氏,一些电话号码,一个电子邮件地址,一个经理,直接报告,最后是他或她工作的项目。 我们需要能够在列表视图中显示人员,在详细信息视图中显示给定人员,允许用户创建,编辑和删除人员等等。 例如,下面是列表视图的外观,至少现在是这样:



这是我们的详细信息视图的外观:



人与项目之间的关系具有关联的角色。 这种关系也是协作者列表的基础:如果至少有一个项目是他们两个成员,那么两个人就是协作者。

我们的简单要求应该足以显示编写Spring Data Neo4j代码的感觉。

创建人员和项目成员实体

首先,我们将创建人。 我已经取消了验证和JAXB批注,因为它们与我们当前的目的无关:

package org.skydingo.skybase.model;import java.util.Set;
import org.neo4j.graphdb.Direction;
import org.skydingo.skybase.model.relationship.ProjectMembership;
import org.springframework.data.neo4j.annotation.*;
import org.springframework.data.neo4j.support.index.IndexType;@NodeEntity
public class Person implements Comparable<Person> {@GraphId private Long id;@Indexed(indexType = IndexType.FULLTEXT, indexName = "searchByUsername")private String username;private String firstName, lastName, title, workPhone, mobilePhone, email;@RelatedTo(type = "REPORTS_TO")private Person manager;@RelatedTo(type = "REPORTS_TO", direction = Direction.INCOMING)private Set<Person> directReports;@RelatedToVia(type = "MEMBER_OF")private Set<ProjectMembership> memberships;public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }... other accessor methods ...public Person getManager() { return manager; }public void setManager(Person manager) { this.manager = manager; }public Set<Person> getDirectReports() { return directReports; }public void setDirectReports(Set<Person> directReports) {this.directReports = directReports;}public Iterable<ProjectMembership> getMemberships() { return memberships; }public ProjectMembership memberOf(Project project, String role) {ProjectMembership membership = new ProjectMembership(this, project, role);memberships.add(membership);return membership;}... equals(), hashCode(), compareTo() ...
}

我们使用许多注释来放置结构。 让我们从节点及其属性开始。 然后,我们将研究节点之间的简单关系。 然后,我们看一下所谓的关系实体,它们基本上是奇特的关系。 首先,这是我们的域模型的抽象表示:

现在让我们看一些细节。

节点及其属性 。 当我们有一个节点支持的实体时,首先我们用@NodeEntity注释对其进行注释。 大多数简单的节点属性(即与其他节点没有关系的属性)都会随处可见。 请注意,我不必注释firstName,lastName,email等。 Spring Data Neo4j将在那里自动处理映射。

但是有两个例外。 第一个是我将@GraphId放在我的id属性上。 这告诉Spring Data Neo4j这是一个我们可以用于查找的标识符。 另一个是@Indexed注释,该注释(惊奇)为所讨论的属性创建了一个索引。 当您想要替代基于ID的查找时,这很有用。

现在我们来看一下关系。 概括地说,有简单的关系和更高级的关系。 我们将从简单的开始。

简单的关系 。 从低层次上来说,Neo4j是一个图形数据库,因此我们可以用图形理论术语来讨论图形,例如节点,边,有向边,DAG等。 但是这里我们使用图进行领域建模,因此我们根据更高层次的领域建模概念来解释低层次的图形概念。 Spring Data Neo4j使用的语言是“节点实体”代表节点,“关系”代表边缘。

我们的Person CI有一个简单的关系,称为REPORTS_TO,它与人们相关联,因此我们可以对报告层次结构进行建模。 Person有两个用于此关系的字段:manager和directReports。 这些是具有相同关系的相对站点。 我们使用@RelatedTo(type =“ REPORTS_TO”)注释这些字段。 注释还具有一个direction元素,其默认值为Direction.OUTGOING,这意味着“此”节点为边缘尾部。 这就是为什么我们为directReports字段明确指定direction = Direction.INCOMING的原因。

这在数据库中是什么样的? Neoclipse揭示了一切。 以下是一些报告关系示例(单击图像可查看大图):

(小写:有一个@Fetch注释-我们待会儿会看到它-告诉Spring Data Neo4j渴望加载相关实体。出于某种原因,我不必在管理器和直接报表关系中使用它,我不知道为什么。如果有人知道,我将不胜感激。

关系实体 。 除了人与人之间的REPORTS_TO关系之外,我们还关心人与项目之间的MEMBER_OF关系。 这比REPORTS_TO关系更有趣,因为MEMBER_OF具有关联的属性-角色-类似于向RDBMS中的链接表添加列,正如我在上一篇文章对Brig的答复中提到的那样。 Person.memberOf()方法提供了一种使用特殊ProjectMembership“关系实体”将人员分配到项目的便捷方法。 这是代码:

package org.skydingo.skybase.model.relationship;import org.skydingo.skybase.model.Person;
import org.skydingo.skybase.model.Project;
import org.springframework.data.neo4j.annotation.*;@RelationshipEntity(type = "MEMBER_OF")
public class ProjectMembership {@GraphId private Long id;@Fetch @StartNode private Person person;@Fetch @EndNode private Project project;private String role;public ProjectMembership() { }public ProjectMembership(Person person, Project project, String role) {this.person = person;this.project = project;this.role = role;}public Person getPerson() { return person; }public void setPerson(Person person) { this.person = person; }public Project getProject() { return project; }public void setProject(Project project) { this.project = project; }public String getRole() { return role; }public void setRole(String role) { this.role = role; }... equals(), hashCode(), toString() ...}

像Person一样,ProjectMembership是一个实体,但它是一个关系实体。 我们使用@RelationshipEntity(type =“ MEMBER_OF”)将其标记为关系实体,并且与Person一样,将@GraphId用作id属性。 @StartNode和@EndNode注释分别指示边缘的尾部和头部。 @Fetch告诉Spring Data Neo4j急切地加载节点。 默认情况下,Spring Data Neo4j不会急于加载关系,因为可能会将整个图形加载到内存中。

创建人仓库

这是我们的PersonRepository接口:

package org.skydingo.skybase.repository;import java.util.Set;
import org.skydingo.skybase.model.Person;
import org.skydingo.skybase.model.Project;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.GraphRepository;public interface PersonRepository extends GraphRepository<Person> {Person findByUsername(String username);@Query("start project=node({0}) match project<--person return person")Set<Person> findByProject(Project project);@Query("start person=node({0}) " +"match person-[:MEMBER_OF]->project<-[:MEMBER_OF]-collaborator " +"return collaborator")Set<Person> findCollaborators(Person person);
}

我在上一篇文章中指出,我们需要做的就是扩展GraphRepository接口。 Spring Data自动生成实现。

对于findByUsername(),Spring Data可以找出所需的查询。 对于其他两个查询,我们使用@Query和Cypher查询语言来指定所需的结果集。 查询中的{0}指的是finder方法参数。 在findCollaborators()查询中,我们使用[:MEMBER_OF]指示我们要遵循的关系。 这些返回Set而不是Iterables以消除重复项。

创建网页控制器

我们不会在这里介绍整个控制器,但是会介绍一些代表性的方法。 假设我们已经将一个PersonRepository注入到控制器中。

创建一个人 。 要创建一个人,我们可以使用以下方法:

@RequestMapping(value = "", method = RequestMethod.POST)
public String createPerson(Model model, @ModelAttribute Person person) {personRepo.save(person);return "redirect:/people?a=created";
}

再一次,我们忽略了验证。 我们要做的就是在存储库上调用save()方法。 这也是更新的工作方式。

寻找所有人 。 接下来,这是我们如何吸引所有人的方法:

@RequestMapping(value = "", method = RequestMethod.GET)
public String getPersonList(Model model) {Iterable<Person> personIt = personRepo.findAll();List<Person> people =new ArrayList<Person>(IteratorUtil.asCollection(personIt));Collections.sort(people);model.addAttribute(people);return "personList";
}

我们必须做一些工作才能使PersonRepository.findAll()返回的Iterable成为所需的格式。 Neo4j(org.neo4j.helpers.collection.IteratorUtil)随附的IteratorUtil在此提供帮助。

寻找一个人 。 在这里,我们要显示我们上面建立的个人详细信息。 与findAll()一样,我们必须做一些自我按摩:

@RequestMapping(value = "/{username}", method = RequestMethod.GET)
public String getPersonDetails(@PathVariable String username, Model model) {Person person = personRepo.findByUsername(username);List<ProjectMembership> memberships =CollectionsUtil.asList(person.getMemberships());List<Person> directReports =CollectionsUtil.asList(person.getDirectReports());List<Person> collaborators =CollectionsUtil.asList(personRepo.findCollaborators(person));Collections.sort(directReports);Collections.sort(collaborators);model.addAttribute(person);model.addAttribute("memberships", memberships);model.addAttribute("directReports", directReports);model.addAttribute("collaborators", collaborators);return "personDetails";
}

如果要查看JSP,请访问Skybase GitHub网站 。

配置APP

最后,这是我的beans-service.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"xmlns:p="http://www.springframework.org/schema/p"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/data/neo4jhttp://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd"><context:property-placeholderlocation="classpath:/spring/environment.properties" /><context:annotation-config /><context:component-scan base-package="org.skydingo.skybase.service" /><tx:annotation-driven mode="proxy" /><neo4j:config storeDirectory="${graphDb.dir}" /><neo4j:repositories base-package="org.skydingo.skybase.repository" />
</beans>

Neo4j具有一个基于POJO的基本映射模型和一个基于AspectJ的高级映射模型。 在此博客文章中,我们一直在使用基于POJO的基本方法,因此我们不需要包括与AspectJ相关的配置,例如<context:spring-configured>。

在那里,这就是Neo4j支持的Person CI。 编码愉快!

要更详细地查看代码或参与Skybase开发,请访问Skybase GitHub网站

参考:来自Skydingo博客的JCG合作伙伴 Willie Wheeler的Spring Data Neo4j进行领域建模 。

相关文章 :

  • Spring Data JPA的持久层
  • 基于事务的基于事件的NOSQL存储
  • SQL或NOSQL:这是问题吗?
  • 什么是NoSQL?
  • Cassandra,MongoDB,CouchDB,Redis,Riak,HBase比较

翻译自: https://www.javacodegeeks.com/2012/01/domain-modeling-with-spring-data-neo4j.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374509.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux多线程_Java+Linux,深入内核源码讲解多线程之进程

之前写了两篇文章&#xff0c;都是针对Linux这个系统的&#xff0c;为什么?我为什么这么喜欢写这个系统的知识&#xff0c;可能就是为了今天的内容多线程系列&#xff0c;现在多线程不是一个面试重点 啊&#xff0c;那如果你能深入系统内核回答这个知识点&#xff0c;面试官会…

ipad连接电脑_这些应用让iPad生产力分分钟UP

IT时报见习记者 钱奕昀用iPad办公这件事&#xff0c;多年前网友就在讨论&#xff0c;最常见的还是那句“买前生产力&#xff0c;买后爱奇艺”。很长一段时间里&#xff0c;它的生产力属性都是弱于娱乐属性的。其实&#xff0c;作为PC端和移动端的形态中和&#xff0c;iPad可以…

Mac OSX 快捷键命令行

ctrlshift 快速放大dock的图标会暂时放大&#xff0c;而如果你开启了dock放大CommandOptionW 将所有窗口关闭CommandW 将当前窗口关闭(可以关闭Safari标签栏,很实用) CommandOptionM …

将JavaFX 2.0与Swing和SWT集成

JavaFX 2.0对JavaFX的改进之一是可以更轻松地与Swing和SWT进行互操作 。 一些在线资源记录了如何完成此操作。 其中包括将JavaFX集成到Swing应用程序和SWT Interop中 。 但是&#xff0c;在有效的类级Javadoc文档的一个很好的示例中&#xff0c;各自的JavaFX类javafx.embed.swi…

wifi rssi 计算 距离_WiFi和WLAN是一样的?真相在这里~别再傻傻分不清了

我们通常上网的时候会说连接WiFi如果注意到无线网络的名称就会发现手机的连接显示是WLAN别再将WiFI和WLAN搞混了&#xff01;二者的定义WLANWLAN的全称为 Wireless Local Area Networks,中文意思为无线局域网络&#xff0c;是一种数据传输系统。它是利用射频技术进行数据传输&a…

实用的it知识学习_怎样能更快更好的学习好书法?分享一些比较实用的理论知识...

如何能更快更高效的学习书法&#xff1f;首先了解一些书法理论知识是很有必要的&#xff01;它能让你在学习书法的过程中不至于迷茫 &#xff01;能助你更快学好书法&#xff01;一、书论在实践中产生我们大部分人都觉得学习书法可以没有理论&#xff0c;但不可无技法。但理论和…

android 上下滚动文字_计算机毕设项目004之Android系统在线小说阅读器

计算机毕设项目004之Android系统在线小说阅读器一. 项目名称基于Android系统的在线小说阅读器二. 项目简介项目中的角色功能&#xff1a;支持翻页动画:仿真翻页、覆盖翻页、上下滚动翻页等翻页效果。支持页面定制:亮度调节、背景调节、字体大小调节支持全屏模式(含有虚拟按键的…

基线检查工具_最新版CAD燕秀工具箱2.87(支持20042021)

好课推荐&#xff1a;零基础CAD&#xff1a;点我CAD家装&#xff1a;点我 周站长CAD&#xff1a;点我CAD机械&#xff1a;点我revit教程&#xff1a;点我CAD建筑&#xff1a;点我CAD三维&#xff1a;点我全屋定制&#xff1a;点我 ps教程&#xff1a;点我苹果版CAD:点我 3dmax教…

关于java.lang.ArithmeticException

java.lang.ArithmeticException “数学运算异常”&#xff0c;可能是自己的数学运算公式出现了错误、违反了数学运算规则。错误记录&#xff1a; 出错原因&#xff1a; a % b 中b不能为0

Java EE 6与Spring Framework:技术决策过程

在过去的几个月中&#xff0c;我们经历了这个决策过程&#xff1a;为Java平台上的企业开发选择哪种技术堆栈&#xff1f; 有多种选择。 但是&#xff0c;我们深入讨论的是&#xff1a;纯Java EE 6堆栈与带有Java EE的Spring。 以下博客文章总结了当您考虑这些技术堆栈选项之一时…

允许服务与桌面交互_vivo 正式推出 Origin OS,融合自然设计与全新交互

点击右上角关注我们&#xff0c;每天给您带来最新最潮的科技资讯&#xff0c;让您足不出户也知道科技圈大事&#xff01;今天下午&#xff0c;vivo 推出了全新 Origin OS 手机系统。它采用了源于自然界的设计理念&#xff0c;同时加入了全新并且允许用户进行深度自定义的交互方…

dll 源码_【技术分享】 | 一个JAVA内存马的源码分析

前言偶然接触到了这样一个JAVA内存马&#xff0c;其作者也是冰蝎的作者&#xff0c;项目地址&#xff1a;https://github.com/rebeyond/memShell正好最近在接触JAVA&#xff0c;借此机会学习下大佬的代码&#xff0c;对自己的编程思路也有了一定的提升。当然笔者只是一个脚本小…

ThunderSearch(闪电搜索器)_网络空间搜索引擎工具_信息收集

文章目录 ThunderSearch简介1 项目地址2 使用方式2.1 配置文件config.json说明2.2 构建和运行 3 使用式例 ThunderSearch简介 ThunderSearch&#xff08;闪电搜索器&#xff09;是一款使用多个(【支持Fofa、Shodan、Hunter、Zoomeye、360Quake网络空间搜索引擎】网络空间搜索引…

每个人都知道MVC…

从一个最近的博客中&#xff0c;您可能已经了解到我最近一直在进行一些采访&#xff0c;因为他们是针对Web应用程序开发人员的&#xff0c;所以我问的一个问题是“您能解释一下MVC模式是什么吗&#xff1f;”&#xff0c;值得称赞的是&#xff0c;每个候选人知道答案。 对于不认…

r语言ggplot2 多线图绘制图例_plotnine: Python版的ggplot2作图库

腾讯课堂 | Python网络爬虫与文本数据分析同样的基本作图任务&#xff0c;plotnine比matplotlib和seaborn代码量少&#xff0c;更美观。所以我又重新发一遍&#xff0c;大家可以先收藏起来&#xff0c;后面总有用到的时候~R语言的ggplot2绘图能力超强&#xff0c;python虽有mat…

单元和集成测试的代码覆盖率

我最近在一个宠物项目中着手构建自动化的UI&#xff08;集成&#xff09;测试以及普通的单元测试。 我想将所有这些集成到我的Maven构建中&#xff0c;并提供代码覆盖率报告&#xff0c;以便我可以了解测试覆盖率不足的区域。 我不仅发布了项目的源代码&#xff0c;还整理了一个…

python学生分布_Python数据分析实战之分布分析

前言 本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。 作者&#xff1a;严小样儿 分布分析法&#xff0c;一般是根据分析目的&#xff0c;将数据进行分组&#xff0c;研究各组别分布规律的一种分析方法。…

hls fifo_HLS优化方法DATAFLOW你用了吗

上期内容&#xff1a;异步跨时钟域电路该怎么约束DATAFLOW作为HLS的一种优化方法&#xff0c;对于改善吞吐率(Throughput)、降低延迟(Latency)非常有效。DATAFLOW的作用对象DATAFLOW可以作用于函数&#xff0c;也可以作用于for循环。如下图所示(图片来源Figure62, Figure 63, u…

在Hibernate,EhCache,Quartz,DBCP和Spring中启用JMX

继续使用JMX的过程&#xff08;请参阅&#xff1a; 人类JMX &#xff09;&#xff0c;我们将学习如何在一些流行的框架中启用JMX支持&#xff08;通常是统计和监视功能&#xff09;。 这些信息大部分都可以在项目的主页上找到&#xff0c;但是我决定在收集这些信息的同时&#…

400多万微信用户如何“变现”?凯叔说了五大秘诀与教训

凯叔&#xff0c;原名王凯&#xff0c;自媒体“凯叔讲故事”创始人&#xff0c;近日在狮享家班委会上做了分享&#xff0c;全是实实在在的实验性方法论。以下是王凯的分享内容&#xff0c;整理 / 垅青 我讲的主题叫“基于内容的MVP探索”&#xff0c;MVP是什么东西&#xff1f;…