c# neo4jClient 在事务中添加两个具有新关系的新节点
c# neo4jClient adding two new nodes with a new relationship inside a transaction
我已经使用 neo4JClient 玩了几天,并且有一个工作场所,其中包含我想要建模的一小部分数据实体。你在这里看到的是一个孤立的例子,试图找出问题所在。
所提供的代码应该复制和粘贴,并且 运行 提供正确的参考资料;
该代码说明核心方法在事务外正常工作,但在第一次尝试在同一事务内的两个新节点之间创建新关系时失败。
我不知道我是否落入新手陷阱 a) 一般的 neo4j,neo4jClient
具体来说,或者交易处理存在真正的问题。我假设我错了,我的想法是缺乏的,但我无法在任何地方找到另一个相关的问题来给我一个线索。
简而言之,我的用例是这样的;
As a new user I want to register as an owner with my current identity
and be able to add my list of related assets to my portfolio.
我知道这可能不是执行此建议的正确或最有效的方法,我们将不胜感激。
以下代码应说明有效的用例和失败的用例;
我得到的异常是;
System.InvalidOperationException was unhandled HResult=-2146233079
Message=Cannot be done inside a transaction scope.
Source=Neo4jClient StackTrace:
at Neo4jClient.GraphClient.CheckTransactionEnvironmentWithPolicy(IExecutionPolicy
policy) in D:\temp4a765\Neo4jClient\GraphClient.cs:line 797
at Neo4jClient.GraphClient.CreateRelationship[TSourceNode,TRelationship](NodeReference`1
sourceNodeReference, TRelationship relationship) in
D:\temp4a765\Neo4jClient\GraphClient.cs:line 350
at ConsoleApplication1.Example.CreateOwnerNode(IGraphClient client, Owner owner, Identity identity) in
.
.
. InnerException:
using System;
using System.Linq;
using System.Transactions;
using Neo4jClient;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var example = new Example();
}
}
public class Example
{
public Example()
{
var rootUri = new Uri("http://localhost:7474/db/data/");
var username = "neo4j";
var neo4jneo4j = "neo4j";
IGraphClient client = new GraphClient(rootUri, username, neo4jneo4j);
client.Connect();
Node<Owner> ownerNode;
Node<Identity> identityNode;
// whole thing outside tranaction
ownerNode = CreateOwnerNode(client, new Owner(), new Identity());
// individually outside transaction
ownerNode = CreateOwner(client, new Owner());
identityNode = CreateIdentity(client, new Identity());
GiveOwnerAnIdentity(client, ownerNode, identityNode);
// individually inside a transaction
using (var scope = new TransactionScope())
{
ownerNode = CreateOwner(client, new Owner());
identityNode = CreateIdentity(client, new Identity());
GiveOwnerAnIdentity(client, ownerNode, identityNode);
scope.Complete();
}
// whole thing inside a transaction
using (var scope = new TransactionScope())
{
ownerNode = CreateOwnerNode(client, new Owner(), new Identity());
scope.Complete();
}
//TODO: Something else with ownerNode
}
public void GiveOwnerAnIdentity(IGraphClient client, Node<Owner> ownerNode, Node<Identity> identityNode)
{
client.CreateRelationship(ownerNode.Reference, new Has(identityNode.Reference));
}
public Node<Identity> CreateIdentity(IGraphClient client, Identity identity)
{
var identityKey = KeyFor<Identity>();
return client.Cypher.Create(identityKey)
.WithParams(new { identity })
.Return(o => o.Node<Identity>())
.Results
.Single();
}
public Node<Owner> CreateOwner(IGraphClient client, Owner owner)
{ var ownerKey = KeyFor<Owner>();
return client.Cypher.Create(ownerKey)
.WithParams(new { owner })
.Return(o => o.Node<Owner>())
.Results.Single();
}
/// <summary>
/// Create a node for an owner along with its nominated identity, relate the owner as having an identity
/// </summary>
/// <param name="client">The <see cref="Neo4jClient" /> instance</param>
/// <param name="owner">The <see cref="Identity" /> instance</param>
/// <param name="identity">The <see cref="Identity" /> instance</param>
/// <returns>The created <see cref="Owner" /> node instance for additional relationships</returns>
public Node<Owner> CreateOwnerNode(IGraphClient client, Owner owner, Identity identity)
{
var ownerKey = KeyFor<Owner>();
var identityKey = KeyFor<Identity>();
var ownerNode =
client.Cypher.Create(ownerKey)
.WithParams(new {owner})
.Return(o => o.Node<Owner>())
.Results.Single();
var identityNode = client.Cypher.Create(identityKey)
.WithParams(new {identity})
.Return(o => o.Node<Identity>())
.Results
.Single();
client.CreateRelationship(ownerNode.Reference, new Has(identityNode.Reference));
return ownerNode;
}
/// <summary>
/// Conform a Cypher create text for a type
/// </summary>
/// <typeparam name="TObject">The type to handle</typeparam>
/// <returns>A string like "{o:TObject {tobject})</returns>
public string KeyFor<TObject>()
{
var name = typeof(TObject).Name;
return $"(o:{name} {{{name.ToLower()}}})";
}
public abstract class Nodebase
{
public Guid Id { get; set; }
public Nodebase()
{
Id = Guid.NewGuid(); // make sure each node is always uniquely identifiable
}
}
/// <summary>
/// Owner node , properties to be added later
/// </summary>
public class Owner
{
}
/// <summary>
/// Identity node , properties to be added later
/// </summary>
public class Identity
{
}
/// <summary>
/// The <see cref="Owner" /> Has an <see cref="Identity" />
/// </summary>
public class Has : Relationship,
IRelationshipAllowingSourceNode<Owner>,
IRelationshipAllowingTargetNode<Identity>
{
internal Has(NodeReference<Identity> targetNode)
: base(targetNode)
{
}
public override string RelationshipTypeKey => GetType().Name.ToUpper();
}
}
}
更新:
好的,还有更多信息,但还不是解决方案。
一如既往,如果我说错了树,请权衡一下。
关于为什么交易如此难以处理(到目前为止)的更多线索。
我根据 Chris Skardons 回复更正了我的代码,这是正确的,它解决了创建问题,但没有解决在事务中创建所需对象并取回节点引用的原则问题。然而,它确实创建了节点和关系。我认为 neo4jClient 某处存在错误。
请求实际上成功了,但客户端的处理失败了,可能是因为我正在请求一个节点引用以便稍后在我的代码中使用。
这个有希望的最终问题现在集中在 GraphClient 处理事务中的以下方法。
看起来,当您围绕 Cypher 查询包装交易时,它的所有步骤都在标准 Cypher API 方法处理之外,并通过交易 API.
处理所有内容
这导致了截然不同的反应,我认为这就是问题所在。
我下载了整个 Neo4jClient 代码库并将其直接连接到我的示例代码解决方案而不是 NuGet 包中,因此我可以在必要时逐步执行所有代码到 HttpClient。
我还连接了 fiddler 来查看 REST 消息。更多内容见下文。
这两个 fiddler 会话更详细地显示了正在发生的事情; (请原谅冗长的帖子,因为它的相关数据可以了解正在发生的事情。)
交易之外
POST http : //localhost:7474/db/data/cypher HTTP/1.1
Accept : application / json;
stream = true
X - Stream : true
User - Agent : Neo4jClient / 0.0.0.0
Authorization : Basic bmVvNGo6bmVvNGpuZW80ag ==
Content - Type : application / json;
charset = utf - 8
Host : localhost : 7474
Content - Length : 174
Expect : 100 - continue
{
"query" : "CREATE (o:Owner {owner})\r\nCREATE (i:Identity {identity})\r\nCREATE (o)-[:HAS]->(i)\r\nRETURN o",
"params" : {
"owner" : {},
"identity" : {}
}
}
HTTP / 1.1 200 OK
Date : Wed, 18 May 2016 12 : 03 : 57 GMT
Content - Type : application / json;
charset = UTF - 8;
stream = true
Access - Control - Allow - Origin : *
Content - Length : 1180
Server : Jetty(9.2.9.v20150224)
{
"columns" : ["o"],
"data" : [[{
"extensions" : {},
"metadata" : {
"id" : 53044,
"labels" : ["Owner"]
},
"paged_traverse" : "http://localhost:7474/db/data/node/53044/paged/traverse/{returnType}{?pageSize,leaseTime}",
"outgoing_relationships" : "http://localhost:7474/db/data/node/53044/relationships/out",
"outgoing_typed_relationships" : "http://localhost:7474/db/data/node/53044/relationships/out/{-list|&|types}",
"create_relationship" : "http://localhost:7474/db/data/node/53044/relationships",
"labels" : "http://localhost:7474/db/data/node/53044/labels",
"traverse" : "http://localhost:7474/db/data/node/53044/traverse/{returnType}",
"all_relationships" : "http://localhost:7474/db/data/node/53044/relationships/all",
"all_typed_relationships" : "http://localhost:7474/db/data/node/53044/relationships/all/{-list|&|types}",
"property" : "http://localhost:7474/db/data/node/53044/properties/{key}",
"self" : "http://localhost:7474/db/data/node/53044",
"incoming_relationships" : "http://localhost:7474/db/data/node/53044/relationships/in",
"properties" : "http://localhost:7474/db/data/node/53044/properties",
"incoming_typed_relationships" : "http://localhost:7474/db/data/node/53044/relationships/in/{-list|&|types}",
"data" : {}
}
]]
}
交易内
POST http : //localhost:7474/db/data/transaction HTTP/1.1
Accept : application / json;
stream = true
X - Stream : true
User - Agent : Neo4jClient / 0.0.0.0
Authorization : Basic bmVvNGo6bmVvNGpuZW80ag ==
Content - Type : application / json;
charset = utf - 8
Host : localhost : 7474
Content - Length : 273
Expect : 100 - continue
{
"statements" : [{
"statement" : "CREATE (o:Owner {owner})\r\nCREATE (i:Identity {identity})\r\nCREATE (o)-[:HAS]->(i)\r\nRETURN o",
"resultDataContents" : [],
"parameters" : {
"owner" : {},
"identity" : {}
}
}
]
}
HTTP / 1.1 201 Created
Date : Wed, 18 May 2016 12 : 04 : 00 GMT
Location : http : //localhost:7474/db/data/transaction/585
Content - Type : application / json
Access - Control - Allow - Origin : *
Content - Length : 241
Server : Jetty(9.2.9.v20150224)
{
"commit" : "http://localhost:7474/db/data/transaction/585/commit",
"results" : [{
"columns" : ["o"],
"data" : [{
"row" : [{}
],
"meta" : [{
"id" : 53046,
"type" : "node",
"deleted" : false
}
]
}
]
}
],
"transaction" : {
"expires" : "Wed, 18 May 2016 12:05:00 +0000"
},
"errors" : []
}
我发现这个方法有问题;
public class CypherJsonDeserializer<TResult>
IEnumerable<TResult> ParseInSingleColumnMode(DeserializationContext context, JToken root, string[] columnNames, TypeMapping[] jsonTypeMappings)
接近该方法末尾的行;
var parsed = CommonDeserializerMethods.CreateAndMap(context, newType, elementToParse, jsonTypeMappings, 0);
returns 不在事务中时正确形成的 'parsed' 变量(即它调用 Cypher API URL),但不填充属性该变量在交易中并且正在使用交易 API.
我的问题是,考虑到事务 returns 非常不同的数据是否应该调用此方法?
在那之后,一切都在你的脸上爆炸了。我目前对代码意图的了解还不够多,无法多说。作为 neo4jClient 用户,我还不到一周的时间。
将 neo4jClient 与 fiddler 和本地主机一起使用
在我的调查中,我还发现了与连接 Fiddler 以查看发生了什么有关的其他问题。
我使用 Fiddler 规则技巧将我的本地 URL 命名为 'localneoj4' 而不是 localhost:7474,并在 client.Connect 方法中使用该新名称,这样我可以看到当地的路况。
var rootUri = "http://localneo4j/db/data";
IGraphClient client = new GraphClient(rootUri, username, password);
client.Connect();
按照建议 here 并将其添加到我的规则中;
if (oSession.HostnameIs("localneo4j")) {
oSession.host = "localhost:7474"; }
这导致内部出现错误
public class NeoServerConfiguration
internal static async Task<NeoServerConfiguration> GetConfigurationAsync(Uri rootUri, string username, string password, ExecutionConfiguration executionConfiguration)
这可能影响了许多走这条路的开发人员。
因为 fiddlers 代理效果是在 neo4jClient 的地址概念和服务器的地址概念之间建立一个断开连接。
处理从以下行的连接响应返回的 URI 时出现字符串长度不匹配问题,因为所有 result.* 属性都以“http://localhost:7474/db/data/' but rootUriWithoutUserInfo starts with http://localneo4j/db/data/”
开头
var baseUriLengthToTrim = rootUriWithoutUserInfo.AbsoluteUri.Length - 1;
result.Batch = result.Batch.Substring(baseUriLengthToTrim);
result.Node = result.Node.Substring(baseUriLengthToTrim);
result.NodeIndex = result.NodeIndex.Substring(baseUriLengthToTrim);
result.Relationship = "/relationship"; //Doesn't come in on the Service Root
result.RelationshipIndex = result.RelationshipIndex.Substring(baseUriLengthToTrim);
result.ExtensionsInfo = result.ExtensionsInfo.Substring(baseUriLengthToTrim);
解决此问题的一个快速解决方法是,您在 fiddler 规则中使用的应用程序名称与其长度匹配 'localhost:7474'
更好的解决方法可能是(我已经针对 < == 和 > 相对地址长度对其进行了测试)作为完全消除协议服务器地址和端口的一种方式,但这取决于代码所有者我猜;
private static string CombineTrailingSegments(string result, int uriSegementsToSkip)
{
return new Uri(result).Segments.Skip(uriSegementsToSkip).Aggregate(@"/", (current, item) =>{ return current += item;});
}
then
var uriSegementsToSkip = rootUriWithoutUserInfo.Segments.Length; // which counts the db/data and adjusts for server configuration
result.Batch = CombineTrailingSegments(result.Batch, uriSegementsToSkip);
...
你得到异常是因为你正在使用旧的 API 调用,TransactionScope
实现是针对 Cypher
调用,基本上是:client.Cypher
.
一般来说,Neo4jClient
已经远离 Node<T>
(在某些特定情况下有用)和 Relationship
类型。我认为您的 CreateOwnerNode
应该更像这样:
public Node<Owner> CreateOwnerNode(IGraphClient client, Owner owner, Identity identity)
{
var query = client.Cypher
.Create($"(o:{GetLabel<Owner>()} {{owner}})")
.Create($"(i:{GetLabel<Identity>()} {{identity}})")
.WithParams(new {owner, identity})
.Create("(o)-[:HAS]->(i)")
.Return(o => o.As<Node<Owner>>());
return query.Results.Single();
}
private string GetLabel<TObject>()
{
return typeof(TObject).Name;
}
您想尝试在单个查询中完成尽可能多的工作,如果您正在尝试 - 您将对数据库进行 3 次调用,这将一次完成。
我认为也许值得先使用普通的 Cypher 来习惯它,不应该有任何理由需要使用 CreateRelationship
东西 - 事实上,我' d 说任何时候你离开 .Cypher
位 - 仔细检查以确保它 真的 你想做什么。
我已经使用 neo4JClient 玩了几天,并且有一个工作场所,其中包含我想要建模的一小部分数据实体。你在这里看到的是一个孤立的例子,试图找出问题所在。
所提供的代码应该复制和粘贴,并且 运行 提供正确的参考资料;
该代码说明核心方法在事务外正常工作,但在第一次尝试在同一事务内的两个新节点之间创建新关系时失败。
我不知道我是否落入新手陷阱 a) 一般的 neo4j,neo4jClient 具体来说,或者交易处理存在真正的问题。我假设我错了,我的想法是缺乏的,但我无法在任何地方找到另一个相关的问题来给我一个线索。
简而言之,我的用例是这样的;
As a new user I want to register as an owner with my current identity and be able to add my list of related assets to my portfolio.
我知道这可能不是执行此建议的正确或最有效的方法,我们将不胜感激。
以下代码应说明有效的用例和失败的用例;
我得到的异常是;
System.InvalidOperationException was unhandled HResult=-2146233079
Message=Cannot be done inside a transaction scope.
Source=Neo4jClient StackTrace: at Neo4jClient.GraphClient.CheckTransactionEnvironmentWithPolicy(IExecutionPolicy policy) in D:\temp4a765\Neo4jClient\GraphClient.cs:line 797 at Neo4jClient.GraphClient.CreateRelationship[TSourceNode,TRelationship](NodeReference`1 sourceNodeReference, TRelationship relationship) in D:\temp4a765\Neo4jClient\GraphClient.cs:line 350 at ConsoleApplication1.Example.CreateOwnerNode(IGraphClient client, Owner owner, Identity identity) in . . . InnerException:
using System;
using System.Linq;
using System.Transactions;
using Neo4jClient;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var example = new Example();
}
}
public class Example
{
public Example()
{
var rootUri = new Uri("http://localhost:7474/db/data/");
var username = "neo4j";
var neo4jneo4j = "neo4j";
IGraphClient client = new GraphClient(rootUri, username, neo4jneo4j);
client.Connect();
Node<Owner> ownerNode;
Node<Identity> identityNode;
// whole thing outside tranaction
ownerNode = CreateOwnerNode(client, new Owner(), new Identity());
// individually outside transaction
ownerNode = CreateOwner(client, new Owner());
identityNode = CreateIdentity(client, new Identity());
GiveOwnerAnIdentity(client, ownerNode, identityNode);
// individually inside a transaction
using (var scope = new TransactionScope())
{
ownerNode = CreateOwner(client, new Owner());
identityNode = CreateIdentity(client, new Identity());
GiveOwnerAnIdentity(client, ownerNode, identityNode);
scope.Complete();
}
// whole thing inside a transaction
using (var scope = new TransactionScope())
{
ownerNode = CreateOwnerNode(client, new Owner(), new Identity());
scope.Complete();
}
//TODO: Something else with ownerNode
}
public void GiveOwnerAnIdentity(IGraphClient client, Node<Owner> ownerNode, Node<Identity> identityNode)
{
client.CreateRelationship(ownerNode.Reference, new Has(identityNode.Reference));
}
public Node<Identity> CreateIdentity(IGraphClient client, Identity identity)
{
var identityKey = KeyFor<Identity>();
return client.Cypher.Create(identityKey)
.WithParams(new { identity })
.Return(o => o.Node<Identity>())
.Results
.Single();
}
public Node<Owner> CreateOwner(IGraphClient client, Owner owner)
{ var ownerKey = KeyFor<Owner>();
return client.Cypher.Create(ownerKey)
.WithParams(new { owner })
.Return(o => o.Node<Owner>())
.Results.Single();
}
/// <summary>
/// Create a node for an owner along with its nominated identity, relate the owner as having an identity
/// </summary>
/// <param name="client">The <see cref="Neo4jClient" /> instance</param>
/// <param name="owner">The <see cref="Identity" /> instance</param>
/// <param name="identity">The <see cref="Identity" /> instance</param>
/// <returns>The created <see cref="Owner" /> node instance for additional relationships</returns>
public Node<Owner> CreateOwnerNode(IGraphClient client, Owner owner, Identity identity)
{
var ownerKey = KeyFor<Owner>();
var identityKey = KeyFor<Identity>();
var ownerNode =
client.Cypher.Create(ownerKey)
.WithParams(new {owner})
.Return(o => o.Node<Owner>())
.Results.Single();
var identityNode = client.Cypher.Create(identityKey)
.WithParams(new {identity})
.Return(o => o.Node<Identity>())
.Results
.Single();
client.CreateRelationship(ownerNode.Reference, new Has(identityNode.Reference));
return ownerNode;
}
/// <summary>
/// Conform a Cypher create text for a type
/// </summary>
/// <typeparam name="TObject">The type to handle</typeparam>
/// <returns>A string like "{o:TObject {tobject})</returns>
public string KeyFor<TObject>()
{
var name = typeof(TObject).Name;
return $"(o:{name} {{{name.ToLower()}}})";
}
public abstract class Nodebase
{
public Guid Id { get; set; }
public Nodebase()
{
Id = Guid.NewGuid(); // make sure each node is always uniquely identifiable
}
}
/// <summary>
/// Owner node , properties to be added later
/// </summary>
public class Owner
{
}
/// <summary>
/// Identity node , properties to be added later
/// </summary>
public class Identity
{
}
/// <summary>
/// The <see cref="Owner" /> Has an <see cref="Identity" />
/// </summary>
public class Has : Relationship,
IRelationshipAllowingSourceNode<Owner>,
IRelationshipAllowingTargetNode<Identity>
{
internal Has(NodeReference<Identity> targetNode)
: base(targetNode)
{
}
public override string RelationshipTypeKey => GetType().Name.ToUpper();
}
}
}
更新:
好的,还有更多信息,但还不是解决方案。
一如既往,如果我说错了树,请权衡一下。
关于为什么交易如此难以处理(到目前为止)的更多线索。
我根据 Chris Skardons 回复更正了我的代码,这是正确的,它解决了创建问题,但没有解决在事务中创建所需对象并取回节点引用的原则问题。然而,它确实创建了节点和关系。我认为 neo4jClient 某处存在错误。
请求实际上成功了,但客户端的处理失败了,可能是因为我正在请求一个节点引用以便稍后在我的代码中使用。
这个有希望的最终问题现在集中在 GraphClient 处理事务中的以下方法。
看起来,当您围绕 Cypher 查询包装交易时,它的所有步骤都在标准 Cypher API 方法处理之外,并通过交易 API.
处理所有内容这导致了截然不同的反应,我认为这就是问题所在。
我下载了整个 Neo4jClient 代码库并将其直接连接到我的示例代码解决方案而不是 NuGet 包中,因此我可以在必要时逐步执行所有代码到 HttpClient。
我还连接了 fiddler 来查看 REST 消息。更多内容见下文。
这两个 fiddler 会话更详细地显示了正在发生的事情; (请原谅冗长的帖子,因为它的相关数据可以了解正在发生的事情。)
交易之外
POST http : //localhost:7474/db/data/cypher HTTP/1.1
Accept : application / json;
stream = true
X - Stream : true
User - Agent : Neo4jClient / 0.0.0.0
Authorization : Basic bmVvNGo6bmVvNGpuZW80ag ==
Content - Type : application / json;
charset = utf - 8
Host : localhost : 7474
Content - Length : 174
Expect : 100 - continue
{
"query" : "CREATE (o:Owner {owner})\r\nCREATE (i:Identity {identity})\r\nCREATE (o)-[:HAS]->(i)\r\nRETURN o",
"params" : {
"owner" : {},
"identity" : {}
}
}
HTTP / 1.1 200 OK
Date : Wed, 18 May 2016 12 : 03 : 57 GMT
Content - Type : application / json;
charset = UTF - 8;
stream = true
Access - Control - Allow - Origin : *
Content - Length : 1180
Server : Jetty(9.2.9.v20150224)
{
"columns" : ["o"],
"data" : [[{
"extensions" : {},
"metadata" : {
"id" : 53044,
"labels" : ["Owner"]
},
"paged_traverse" : "http://localhost:7474/db/data/node/53044/paged/traverse/{returnType}{?pageSize,leaseTime}",
"outgoing_relationships" : "http://localhost:7474/db/data/node/53044/relationships/out",
"outgoing_typed_relationships" : "http://localhost:7474/db/data/node/53044/relationships/out/{-list|&|types}",
"create_relationship" : "http://localhost:7474/db/data/node/53044/relationships",
"labels" : "http://localhost:7474/db/data/node/53044/labels",
"traverse" : "http://localhost:7474/db/data/node/53044/traverse/{returnType}",
"all_relationships" : "http://localhost:7474/db/data/node/53044/relationships/all",
"all_typed_relationships" : "http://localhost:7474/db/data/node/53044/relationships/all/{-list|&|types}",
"property" : "http://localhost:7474/db/data/node/53044/properties/{key}",
"self" : "http://localhost:7474/db/data/node/53044",
"incoming_relationships" : "http://localhost:7474/db/data/node/53044/relationships/in",
"properties" : "http://localhost:7474/db/data/node/53044/properties",
"incoming_typed_relationships" : "http://localhost:7474/db/data/node/53044/relationships/in/{-list|&|types}",
"data" : {}
}
]]
}
交易内
POST http : //localhost:7474/db/data/transaction HTTP/1.1
Accept : application / json;
stream = true
X - Stream : true
User - Agent : Neo4jClient / 0.0.0.0
Authorization : Basic bmVvNGo6bmVvNGpuZW80ag ==
Content - Type : application / json;
charset = utf - 8
Host : localhost : 7474
Content - Length : 273
Expect : 100 - continue
{
"statements" : [{
"statement" : "CREATE (o:Owner {owner})\r\nCREATE (i:Identity {identity})\r\nCREATE (o)-[:HAS]->(i)\r\nRETURN o",
"resultDataContents" : [],
"parameters" : {
"owner" : {},
"identity" : {}
}
}
]
}
HTTP / 1.1 201 Created
Date : Wed, 18 May 2016 12 : 04 : 00 GMT
Location : http : //localhost:7474/db/data/transaction/585
Content - Type : application / json
Access - Control - Allow - Origin : *
Content - Length : 241
Server : Jetty(9.2.9.v20150224)
{
"commit" : "http://localhost:7474/db/data/transaction/585/commit",
"results" : [{
"columns" : ["o"],
"data" : [{
"row" : [{}
],
"meta" : [{
"id" : 53046,
"type" : "node",
"deleted" : false
}
]
}
]
}
],
"transaction" : {
"expires" : "Wed, 18 May 2016 12:05:00 +0000"
},
"errors" : []
}
我发现这个方法有问题;
public class CypherJsonDeserializer<TResult>
IEnumerable<TResult> ParseInSingleColumnMode(DeserializationContext context, JToken root, string[] columnNames, TypeMapping[] jsonTypeMappings)
接近该方法末尾的行;
var parsed = CommonDeserializerMethods.CreateAndMap(context, newType, elementToParse, jsonTypeMappings, 0);
returns 不在事务中时正确形成的 'parsed' 变量(即它调用 Cypher API URL),但不填充属性该变量在交易中并且正在使用交易 API.
我的问题是,考虑到事务 returns 非常不同的数据是否应该调用此方法?
在那之后,一切都在你的脸上爆炸了。我目前对代码意图的了解还不够多,无法多说。作为 neo4jClient 用户,我还不到一周的时间。
将 neo4jClient 与 fiddler 和本地主机一起使用
在我的调查中,我还发现了与连接 Fiddler 以查看发生了什么有关的其他问题。
我使用 Fiddler 规则技巧将我的本地 URL 命名为 'localneoj4' 而不是 localhost:7474,并在 client.Connect 方法中使用该新名称,这样我可以看到当地的路况。
var rootUri = "http://localneo4j/db/data";
IGraphClient client = new GraphClient(rootUri, username, password);
client.Connect();
按照建议 here 并将其添加到我的规则中;
if (oSession.HostnameIs("localneo4j")) {
oSession.host = "localhost:7474"; }
这导致内部出现错误
public class NeoServerConfiguration
internal static async Task<NeoServerConfiguration> GetConfigurationAsync(Uri rootUri, string username, string password, ExecutionConfiguration executionConfiguration)
这可能影响了许多走这条路的开发人员。
因为 fiddlers 代理效果是在 neo4jClient 的地址概念和服务器的地址概念之间建立一个断开连接。
处理从以下行的连接响应返回的 URI 时出现字符串长度不匹配问题,因为所有 result.* 属性都以“http://localhost:7474/db/data/' but rootUriWithoutUserInfo starts with http://localneo4j/db/data/”
开头 var baseUriLengthToTrim = rootUriWithoutUserInfo.AbsoluteUri.Length - 1;
result.Batch = result.Batch.Substring(baseUriLengthToTrim);
result.Node = result.Node.Substring(baseUriLengthToTrim);
result.NodeIndex = result.NodeIndex.Substring(baseUriLengthToTrim);
result.Relationship = "/relationship"; //Doesn't come in on the Service Root
result.RelationshipIndex = result.RelationshipIndex.Substring(baseUriLengthToTrim);
result.ExtensionsInfo = result.ExtensionsInfo.Substring(baseUriLengthToTrim);
解决此问题的一个快速解决方法是,您在 fiddler 规则中使用的应用程序名称与其长度匹配 'localhost:7474'
更好的解决方法可能是(我已经针对 < == 和 > 相对地址长度对其进行了测试)作为完全消除协议服务器地址和端口的一种方式,但这取决于代码所有者我猜;
private static string CombineTrailingSegments(string result, int uriSegementsToSkip)
{
return new Uri(result).Segments.Skip(uriSegementsToSkip).Aggregate(@"/", (current, item) =>{ return current += item;});
}
then
var uriSegementsToSkip = rootUriWithoutUserInfo.Segments.Length; // which counts the db/data and adjusts for server configuration
result.Batch = CombineTrailingSegments(result.Batch, uriSegementsToSkip);
...
你得到异常是因为你正在使用旧的 API 调用,TransactionScope
实现是针对 Cypher
调用,基本上是:client.Cypher
.
一般来说,Neo4jClient
已经远离 Node<T>
(在某些特定情况下有用)和 Relationship
类型。我认为您的 CreateOwnerNode
应该更像这样:
public Node<Owner> CreateOwnerNode(IGraphClient client, Owner owner, Identity identity)
{
var query = client.Cypher
.Create($"(o:{GetLabel<Owner>()} {{owner}})")
.Create($"(i:{GetLabel<Identity>()} {{identity}})")
.WithParams(new {owner, identity})
.Create("(o)-[:HAS]->(i)")
.Return(o => o.As<Node<Owner>>());
return query.Results.Single();
}
private string GetLabel<TObject>()
{
return typeof(TObject).Name;
}
您想尝试在单个查询中完成尽可能多的工作,如果您正在尝试 - 您将对数据库进行 3 次调用,这将一次完成。
我认为也许值得先使用普通的 Cypher 来习惯它,不应该有任何理由需要使用 CreateRelationship
东西 - 事实上,我' d 说任何时候你离开 .Cypher
位 - 仔细检查以确保它 真的 你想做什么。