Spring Data Neo4j 在保存过程中插入了意外的关系(边)
Spring Data Neo4j inserts unexpected relations (edges) during save
我使用 Spring Boot 1.5.3 和 2.1.2 的 OGM。 SDN版本是4.2.3,我用的是neo4j 3.2.1数据库。我修改了配置文件以修复 chyper 版本的小问题,所以我使用 chyper 3.1 作为默认语言。
在这个用例中,我只有一个名为类别的简单域 class。每个类别可以有一个 parent 和多个 children 就像一个 class 的树结构。
由于类别数量较多,我更喜欢比数据库所需的磁盘 space 更好的性能。这是我的域名 class:
@NodeEntity
public class Category {
@GraphId
Long id;
@Convert(UuidStringConverter.class)
@Index(unique = true, primary = true)
UUID uuid;
@DateString("yy-MM-dd")
private Date dateAdded;
@Index(unique = true, primary = false)
private String name;
@Relationship(type = "parent", direction = Relationship.OUTGOING)
private Category parent;
@Relationship(type = "children", direction = Relationship.OUTGOING)
private Set<Category> children;
public Category() {
dateAdded = new Date();
uuid = UUID.randomUUID();
}
public Category(String name) {
this();
this.name = name;
}
public Category(String name, Category parent) {
this(name);
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getParent() {
return parent;
}
public void setParent(Category parent) {
this.parent = parent;
}
public UUID getUuid() {
return uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
/**
* @return the dateAdded
*/
public Date getDateAdded() {
return dateAdded;
}
/**
* @param dateAdded
* the dateAdded to set
*/
public void setDateAdded(Date dateAdded) {
this.dateAdded = dateAdded;
}
/**
* @return the children
*/
public Set<Category> getChildren() {
return children;
}
/**
* @param children
* the children to set
*/
public void setChildren(Set<Category> children) {
this.children = children;
}
public void addChildren(Category c) {
if (children == null) {
children = new HashSet<>();
}
children.add(c);
}
public void removeChildren(Category c) {
if (children != null) {
children.remove(c);
if (children.size() == 0) {
children = null;
}
};
}
public String toString(){
return name;
}
}
实际上,没有必要将类别的 parent 和 children 的引用保留为 neo4j "direction agnostic",但这是由于性能相关问题。
SDN 的非常奇怪的行为是,如果我创建一个类别 (Non-fiction) 和一个子类别(数学),一切正常。如果我在同一个主类别下创建一个新的子类别(生物),那么前一个子类别和一个主类别(数学和 Non-fiction)之间会出现意想不到的关系。
日志显示如下:
Create Non-fiction main category
2017-06-14 09:47:06.312 DEBUG 6788 --- [nio-8083-exec-4] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@241797fe
2017-06-14 09:47:06.331 INFO 6788 --- [nio-8083-exec-4] o.n.o.drivers.http.request.HttpRequest : Thread: 21, url: http://neo4j:password@localhost:7474/db/data/transaction/commit, request: {"statements":[{"statement":"MATCH (n:`Category`) WHERE n.`name` = { `name_0` } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)","parameters":{"name_0":"Non-fiction"},"resultDataContents":["graph","row"],"includeStats":false}]}
2017-06-14 09:47:06.390 INFO 6788 --- [nio-8083-exec-4] o.n.o.drivers.http.request.HttpRequest : Thread: 21, url: http://localhost:7474/db/data/transaction/23, request: {"statements":[{"statement":"MATCH (n) WHERE n.uuid = { id } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{"id":"3a497cec-d67c-4c44-ab86-e6639dc60d13"},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:47:06.465 INFO 6788 --- [nio-8083-exec-4] o.n.o.drivers.http.request.HttpRequest : Thread: 21, url: http://localhost:7474/db/data/transaction/24, request: {"statements":[{"statement":"UNWIND {rows} as row MERGE (n:`Category`{uuid: row.props.uuid}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, row.type as type","parameters":{"rows":[{"nodeRef":-684249223,"type":"node","props":{"name":"Non-fiction","uuid":"3a497cec-d67c-4c44-ab86-e6639dc60d13","dateAdded":"17-06-14"}}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:47:06.545 INFO 6788 --- [nio-8083-exec-4] h.b.services.CategoryServiceImpl : Non-fiction category were created
2017-06-14 09:47:06.547 INFO 6788 --- [nio-8083-exec-4] o.n.o.drivers.http.request.HttpRequest : Thread: 21, url: http://localhost:7474/db/data/transaction/25, request: {"statements":[{"statement":"MATCH (n:`Category`) WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:47:06.571 DEBUG 6788 --- [nio-8083-exec-4] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@241797fe
Create Math subcategory of Non-fiction parent category
2017-06-14 09:48:26.865 DEBUG 6788 --- [nio-8083-exec-7] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@241797fe
2017-06-14 09:48:26.881 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://neo4j:password@localhost:7474/db/data/transaction/commit, request: {"statements":[{"statement":"MATCH (n:`Category`) WHERE n.`name` = { `name_0` } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)","parameters":{"name_0":"Math"},"resultDataContents":["graph","row"],"includeStats":false}]}
2017-06-14 09:48:26.916 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://localhost:7474/db/data/transaction/30, request: {"statements":[{"statement":"MATCH (n) WHERE n.uuid = { id } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{"id":"3a839cc1-9af7-45fd-a29c-bfe96705655e"},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:48:26.939 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://localhost:7474/db/data/transaction/31, request: {"statements":[{"statement":"UNWIND {rows} as row MERGE (n:`Category`{uuid: row.props.uuid}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, row.type as type","parameters":{"rows":[{"nodeRef":-1188832417,"type":"node","props":{"name":"Math","uuid":"3a839cc1-9af7-45fd-a29c-bfe96705655e","dateAdded":"17-06-14"}}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:48:26.995 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://localhost:7474/db/data/transaction/31, request: {"statements":[{"statement":"UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MERGE (startNode)-[rel:`parent`]->(endNode) RETURN row.relRef as ref, ID(rel) as id, row.type as type","parameters":{"rows":[{"startNodeId":7,"relRef":-240693881,"type":"rel","endNodeId":6}]},"resultDataContents":["row"],"includeStats":false},{"statement":"UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MERGE (startNode)-[rel:`children`]->(endNode) RETURN row.relRef as ref, ID(rel) as id, row.type as type","parameters":{"rows":[{"startNodeId":6,"relRef":-12081903,"type":"rel","endNodeId":7}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:48:27.288 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://localhost:7474/db/data/transaction/32, request: {"statements":[{"statement":"MATCH (n:`Category`) WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:48:27.344 DEBUG 6788 --- [nio-8083-exec-7] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@241797fe
Create Biology subcategory of Non-fiction parent category
2017-06-14 09:51:12.367 DEBUG 6788 --- [nio-8083-exec-1] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@241797fe
2017-06-14 09:51:12.385 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://neo4j:password@localhost:7474/db/data/transaction/commit, request: {"statements":[{"statement":"MATCH (n:`Category`) WHERE n.`name` = { `name_0` } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)","parameters":{"name_0":"Biology"},"resultDataContents":["graph","row"],"includeStats":false}]}
2017-06-14 09:51:12.394 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://localhost:7474/db/data/transaction/37, request: {"statements":[{"statement":"MATCH (n) WHERE n.uuid = { id } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{"id":"8004d142-85c5-461b-862e-aee7ddfc90fa"},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:51:12.405 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://localhost:7474/db/data/transaction/38, request: {"statements":[{"statement":"UNWIND {rows} as row MERGE (n:`Category`{uuid: row.props.uuid}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, row.type as type","parameters":{"rows":[{"nodeRef":-1174392366,"type":"node","props":{"name":"Biology","uuid":"8004d142-85c5-461b-862e-aee7ddfc90fa","dateAdded":"17-06-14"}}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:51:12.414 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://localhost:7474/db/data/transaction/38, request: {"statements":[{"statement":"UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MERGE (startNode)-[rel:`parent`]->(endNode) RETURN row.relRef as ref, ID(rel) as id, row.type as type","parameters":{"rows":[{"startNodeId":8,"relRef":-1580985829,"type":"rel","endNodeId":6}]},"resultDataContents":["row"],"includeStats":false},{"statement":"UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MERGE (startNode)-[rel:`children`]->(endNode) RETURN row.relRef as ref, ID(rel) as id, row.type as type","parameters":{"rows":[{"startNodeId":7,"relRef":-2084880007,"type":"rel","endNodeId":6},{"startNodeId":6,"relRef":-38658551,"type":"rel","endNodeId":8}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:51:12.456 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://localhost:7474/db/data/transaction/39, request: {"statements":[{"statement":"MATCH (n:`Category`) WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:51:12.520 DEBUG 6788 --- [nio-8083-exec-1] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@241797fe
我创建新子类别的代码如下:
@PostMapping("/admin/category/newMid")
String newMidCategory(Model m, @RequestParam("newMidCategory") String newMidCategoryName,
@RequestParam("selectedMainCategory") Category mainCategory) {
if (mainCategory != null) {
Category existing = categoryService.findCategoryByName(newMidCategoryName);
if (existing == null) {
// indeed it is new category
Category newMidCategory = new Category(newMidCategoryName, mainCategory);
mainCategory.addChildren(newMidCategory);
categoryService.insertNewCategory(newMidCategory);
} else {
m.addAttribute("midCatError", ctx.getMessage("error.admin.MidCategoryExistsAlready", null,
new Locale(env.getProperty("spring.mvc.locale"))));
}
} else {
m.addAttribute("midCatError", ctx.getMessage("error.admin.mainCategoryNotSelected", null,
new Locale(env.getProperty("spring.mvc.locale"))));
}
m.addAttribute("midCategories", categoryService.getChildrenOfParent(mainCategory));
m.addAttribute("allMainCategories", categoryService.getAllMainCategories());
return "admin/category :: #categoryForm";
}
经过几个小时的调试,结果发现子类别(数学)children 集有一个非小说类主要类别的成员,因此 OGM 正确映射了它。
问题是我的私有 children 属性 怎么可能在不调用 public 方法 addChildren(Category c) 的情况下被修改。在我的 addChildren 方法中有一个 System.out.println() 行可以查看它何时被调用。它只被调用两次:第一次是在我们添加数学子类别时,第二次是在我们添加生物子类别时。
如果没有 addChildren 调用,Math 子类别有一个 children?
这是什么?
这看起来像是一个错误。
作为解决方法,您也可以尝试对关系字段的设置器进行注释:
@Relationship(type = "parent", direction = Relationship.OUTGOING)
private Category parent;
@Relationship(type = "children", direction = Relationship.OUTGOING)
private Set<Category> children;
@Relationship(type = "parent", direction = Relationship.OUTGOING)
public void setParent(Category parent) {
this.parent = parent;
}
@Relationship(type = "children", direction = Relationship.OUTGOING)
public void setChildren(Set<Category> children) {
this.children = children;
}
如果您可以使用 SDN/OGM 问题模板重现它,那就太好了。 https://github.com/neo4j-examples/neo4j-sdn-ogm-issue-report-template
如果两个字段的端节点类型相同,您可能需要使用与字段相同的@Relationship 来注释设置器。我相信这在 2.1.4 中已修复。 https://github.com/neo4j/neo4j-ogm/issues/361
我使用 Spring Boot 1.5.3 和 2.1.2 的 OGM。 SDN版本是4.2.3,我用的是neo4j 3.2.1数据库。我修改了配置文件以修复 chyper 版本的小问题,所以我使用 chyper 3.1 作为默认语言。
在这个用例中,我只有一个名为类别的简单域 class。每个类别可以有一个 parent 和多个 children 就像一个 class 的树结构。
由于类别数量较多,我更喜欢比数据库所需的磁盘 space 更好的性能。这是我的域名 class:
@NodeEntity
public class Category {
@GraphId
Long id;
@Convert(UuidStringConverter.class)
@Index(unique = true, primary = true)
UUID uuid;
@DateString("yy-MM-dd")
private Date dateAdded;
@Index(unique = true, primary = false)
private String name;
@Relationship(type = "parent", direction = Relationship.OUTGOING)
private Category parent;
@Relationship(type = "children", direction = Relationship.OUTGOING)
private Set<Category> children;
public Category() {
dateAdded = new Date();
uuid = UUID.randomUUID();
}
public Category(String name) {
this();
this.name = name;
}
public Category(String name, Category parent) {
this(name);
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getParent() {
return parent;
}
public void setParent(Category parent) {
this.parent = parent;
}
public UUID getUuid() {
return uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
/**
* @return the dateAdded
*/
public Date getDateAdded() {
return dateAdded;
}
/**
* @param dateAdded
* the dateAdded to set
*/
public void setDateAdded(Date dateAdded) {
this.dateAdded = dateAdded;
}
/**
* @return the children
*/
public Set<Category> getChildren() {
return children;
}
/**
* @param children
* the children to set
*/
public void setChildren(Set<Category> children) {
this.children = children;
}
public void addChildren(Category c) {
if (children == null) {
children = new HashSet<>();
}
children.add(c);
}
public void removeChildren(Category c) {
if (children != null) {
children.remove(c);
if (children.size() == 0) {
children = null;
}
};
}
public String toString(){
return name;
}
}
实际上,没有必要将类别的 parent 和 children 的引用保留为 neo4j "direction agnostic",但这是由于性能相关问题。
SDN 的非常奇怪的行为是,如果我创建一个类别 (Non-fiction) 和一个子类别(数学),一切正常。如果我在同一个主类别下创建一个新的子类别(生物),那么前一个子类别和一个主类别(数学和 Non-fiction)之间会出现意想不到的关系。 日志显示如下:
Create Non-fiction main category
2017-06-14 09:47:06.312 DEBUG 6788 --- [nio-8083-exec-4] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@241797fe
2017-06-14 09:47:06.331 INFO 6788 --- [nio-8083-exec-4] o.n.o.drivers.http.request.HttpRequest : Thread: 21, url: http://neo4j:password@localhost:7474/db/data/transaction/commit, request: {"statements":[{"statement":"MATCH (n:`Category`) WHERE n.`name` = { `name_0` } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)","parameters":{"name_0":"Non-fiction"},"resultDataContents":["graph","row"],"includeStats":false}]}
2017-06-14 09:47:06.390 INFO 6788 --- [nio-8083-exec-4] o.n.o.drivers.http.request.HttpRequest : Thread: 21, url: http://localhost:7474/db/data/transaction/23, request: {"statements":[{"statement":"MATCH (n) WHERE n.uuid = { id } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{"id":"3a497cec-d67c-4c44-ab86-e6639dc60d13"},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:47:06.465 INFO 6788 --- [nio-8083-exec-4] o.n.o.drivers.http.request.HttpRequest : Thread: 21, url: http://localhost:7474/db/data/transaction/24, request: {"statements":[{"statement":"UNWIND {rows} as row MERGE (n:`Category`{uuid: row.props.uuid}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, row.type as type","parameters":{"rows":[{"nodeRef":-684249223,"type":"node","props":{"name":"Non-fiction","uuid":"3a497cec-d67c-4c44-ab86-e6639dc60d13","dateAdded":"17-06-14"}}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:47:06.545 INFO 6788 --- [nio-8083-exec-4] h.b.services.CategoryServiceImpl : Non-fiction category were created
2017-06-14 09:47:06.547 INFO 6788 --- [nio-8083-exec-4] o.n.o.drivers.http.request.HttpRequest : Thread: 21, url: http://localhost:7474/db/data/transaction/25, request: {"statements":[{"statement":"MATCH (n:`Category`) WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:47:06.571 DEBUG 6788 --- [nio-8083-exec-4] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@241797fe
Create Math subcategory of Non-fiction parent category
2017-06-14 09:48:26.865 DEBUG 6788 --- [nio-8083-exec-7] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@241797fe
2017-06-14 09:48:26.881 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://neo4j:password@localhost:7474/db/data/transaction/commit, request: {"statements":[{"statement":"MATCH (n:`Category`) WHERE n.`name` = { `name_0` } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)","parameters":{"name_0":"Math"},"resultDataContents":["graph","row"],"includeStats":false}]}
2017-06-14 09:48:26.916 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://localhost:7474/db/data/transaction/30, request: {"statements":[{"statement":"MATCH (n) WHERE n.uuid = { id } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{"id":"3a839cc1-9af7-45fd-a29c-bfe96705655e"},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:48:26.939 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://localhost:7474/db/data/transaction/31, request: {"statements":[{"statement":"UNWIND {rows} as row MERGE (n:`Category`{uuid: row.props.uuid}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, row.type as type","parameters":{"rows":[{"nodeRef":-1188832417,"type":"node","props":{"name":"Math","uuid":"3a839cc1-9af7-45fd-a29c-bfe96705655e","dateAdded":"17-06-14"}}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:48:26.995 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://localhost:7474/db/data/transaction/31, request: {"statements":[{"statement":"UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MERGE (startNode)-[rel:`parent`]->(endNode) RETURN row.relRef as ref, ID(rel) as id, row.type as type","parameters":{"rows":[{"startNodeId":7,"relRef":-240693881,"type":"rel","endNodeId":6}]},"resultDataContents":["row"],"includeStats":false},{"statement":"UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MERGE (startNode)-[rel:`children`]->(endNode) RETURN row.relRef as ref, ID(rel) as id, row.type as type","parameters":{"rows":[{"startNodeId":6,"relRef":-12081903,"type":"rel","endNodeId":7}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:48:27.288 INFO 6788 --- [nio-8083-exec-7] o.n.o.drivers.http.request.HttpRequest : Thread: 24, url: http://localhost:7474/db/data/transaction/32, request: {"statements":[{"statement":"MATCH (n:`Category`) WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:48:27.344 DEBUG 6788 --- [nio-8083-exec-7] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@241797fe
Create Biology subcategory of Non-fiction parent category
2017-06-14 09:51:12.367 DEBUG 6788 --- [nio-8083-exec-1] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@241797fe
2017-06-14 09:51:12.385 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://neo4j:password@localhost:7474/db/data/transaction/commit, request: {"statements":[{"statement":"MATCH (n:`Category`) WHERE n.`name` = { `name_0` } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)","parameters":{"name_0":"Biology"},"resultDataContents":["graph","row"],"includeStats":false}]}
2017-06-14 09:51:12.394 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://localhost:7474/db/data/transaction/37, request: {"statements":[{"statement":"MATCH (n) WHERE n.uuid = { id } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{"id":"8004d142-85c5-461b-862e-aee7ddfc90fa"},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:51:12.405 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://localhost:7474/db/data/transaction/38, request: {"statements":[{"statement":"UNWIND {rows} as row MERGE (n:`Category`{uuid: row.props.uuid}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, row.type as type","parameters":{"rows":[{"nodeRef":-1174392366,"type":"node","props":{"name":"Biology","uuid":"8004d142-85c5-461b-862e-aee7ddfc90fa","dateAdded":"17-06-14"}}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:51:12.414 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://localhost:7474/db/data/transaction/38, request: {"statements":[{"statement":"UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MERGE (startNode)-[rel:`parent`]->(endNode) RETURN row.relRef as ref, ID(rel) as id, row.type as type","parameters":{"rows":[{"startNodeId":8,"relRef":-1580985829,"type":"rel","endNodeId":6}]},"resultDataContents":["row"],"includeStats":false},{"statement":"UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId MERGE (startNode)-[rel:`children`]->(endNode) RETURN row.relRef as ref, ID(rel) as id, row.type as type","parameters":{"rows":[{"startNodeId":7,"relRef":-2084880007,"type":"rel","endNodeId":6},{"startNodeId":6,"relRef":-38658551,"type":"rel","endNodeId":8}]},"resultDataContents":["row"],"includeStats":false}]}
2017-06-14 09:51:12.456 INFO 6788 --- [nio-8083-exec-1] o.n.o.drivers.http.request.HttpRequest : Thread: 18, url: http://localhost:7474/db/data/transaction/39, request: {"statements":[{"statement":"MATCH (n:`Category`) WITH n MATCH p=(n)-[*0..1]-(m) RETURN p","parameters":{},"resultDataContents":["graph"],"includeStats":false}]}
2017-06-14 09:51:12.520 DEBUG 6788 --- [nio-8083-exec-1] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@241797fe
我创建新子类别的代码如下:
@PostMapping("/admin/category/newMid")
String newMidCategory(Model m, @RequestParam("newMidCategory") String newMidCategoryName,
@RequestParam("selectedMainCategory") Category mainCategory) {
if (mainCategory != null) {
Category existing = categoryService.findCategoryByName(newMidCategoryName);
if (existing == null) {
// indeed it is new category
Category newMidCategory = new Category(newMidCategoryName, mainCategory);
mainCategory.addChildren(newMidCategory);
categoryService.insertNewCategory(newMidCategory);
} else {
m.addAttribute("midCatError", ctx.getMessage("error.admin.MidCategoryExistsAlready", null,
new Locale(env.getProperty("spring.mvc.locale"))));
}
} else {
m.addAttribute("midCatError", ctx.getMessage("error.admin.mainCategoryNotSelected", null,
new Locale(env.getProperty("spring.mvc.locale"))));
}
m.addAttribute("midCategories", categoryService.getChildrenOfParent(mainCategory));
m.addAttribute("allMainCategories", categoryService.getAllMainCategories());
return "admin/category :: #categoryForm";
}
经过几个小时的调试,结果发现子类别(数学)children 集有一个非小说类主要类别的成员,因此 OGM 正确映射了它。
问题是我的私有 children 属性 怎么可能在不调用 public 方法 addChildren(Category c) 的情况下被修改。在我的 addChildren 方法中有一个 System.out.println() 行可以查看它何时被调用。它只被调用两次:第一次是在我们添加数学子类别时,第二次是在我们添加生物子类别时。 如果没有 addChildren 调用,Math 子类别有一个 children? 这是什么?
这看起来像是一个错误。
作为解决方法,您也可以尝试对关系字段的设置器进行注释:
@Relationship(type = "parent", direction = Relationship.OUTGOING)
private Category parent;
@Relationship(type = "children", direction = Relationship.OUTGOING)
private Set<Category> children;
@Relationship(type = "parent", direction = Relationship.OUTGOING)
public void setParent(Category parent) {
this.parent = parent;
}
@Relationship(type = "children", direction = Relationship.OUTGOING)
public void setChildren(Set<Category> children) {
this.children = children;
}
如果您可以使用 SDN/OGM 问题模板重现它,那就太好了。 https://github.com/neo4j-examples/neo4j-sdn-ogm-issue-report-template
如果两个字段的端节点类型相同,您可能需要使用与字段相同的@Relationship 来注释设置器。我相信这在 2.1.4 中已修复。 https://github.com/neo4j/neo4j-ogm/issues/361