在Neo4jClient

问题描述

我在密码中有以下查询

Match(n1: Red)
Where n1.Id = "someId"
Call apoc.path.subgraphAll(n1,{ minLevel: 0,maxLevel: 100,relationshipFilter: "link",labelFilter: "+Red|Blue"})
Yield nodes,relationships
Return nodes,relationships

查询的图形大致具有“红色->蓝色->红色”的结构,其中所有边的类型均为“链接”。

查询在浏览器客户端中产生预期的结果。

我的C#看起来像这样:

string subgraphAll = "apoc.path.subgraphAll";
object optionsObj = new {
                minLevel = 0,maxLevel = 100,relationshipFilter = $"{link}",labelFilter = $"+{Red}|{Blue}",beginSequenceAtStart = "true",bfs = true,filterStartNode = false,limit = -1,//endNodes = null,//terminatorNodes = null,//whitelistNodes = null,//blacklistNodes = null,};
 string options = JObject.FromObject(optionsObj).ToString();

 var query = client.Cypher
     .Match($"(n1:{"Red"})")
     .Where((Red n1) => n1.Id == "someId")
     .Call($"{subgraphAll}(n1,{options})")
     .Yield($"nodes,relationships")
     //figureOut what to do
     .Return<Object>("");
     var result = query.ResultsAsync.Result;

我的问题是:如何使用Neo4J客户端在C#中编写该代码,以及如何在末尾获得类型安全列表(类似List<Red>,List<Blue>,List<Relationship>)。 由于红色和蓝色是C#中的不同类型,因此我看不到如何从查询中反序列化混合的“节点”列表。

请注意,我的示例有些简化。 Nodetypes不是字符串,而是来自我的应用程序中的Enums,以一种安全的方式知道存在哪些节点类型,并且这些类型背后有真实的模型。

我试图突破存储过程的整个参数化,但是代码未经测试,我不知道是否有更好的解决方案。如果有更好的方法,请也提供建议。

我是cypher的新手,所以在这里我需要一些帮助。

我的想法是将节点列表分为两个列表(红色列表和蓝色列表),然后将三个列表输出为匿名对象的属性(如示例中所示)。不幸的是,我的密码还不足以解决它,并且同时转换为c#语法也无济于事。

我主要担心的是,一旦我将其反序列化为一系列未类型化的对象,将它们解析回我的模型中将是一件令人头疼的事。因此,我希望查询能够为我进行整理。

解决方法

在我看来,如果您想沿着将输出解析为Red/Blue类的路线,那么在C#中进行的操作将比在Cypher中进行。 / p>

不幸的是,在这种情况下-我认为使用Neo4j.Driver驱动程序而不是Neo4jClient执行查询会更容易-这是因为目前看来Neo4jClient要删除id(等)属性,您将需要正确地重建图形。

通过4.0.3的客户端,您可以通过以下方式访问Driver

((BoltGraphClient)client).Driver

我使用了一个“电影/人”示例,因为它是我必须处理的数据集,但是原理是相同的,例如:

var queryStr = @"
    Match(n1: Movie)
    Where n1.title = 'The Matrix'
    Call apoc.path.subgraphAll(n1,{ minLevel: 0,maxLevel: 2,relationshipFilter: 'ACTED_IN',labelFilter: '+Movie|Person'})
    Yield nodes,relationships
    Return nodes,relationships
";

var movies = new List<Movie>();
var people = new List<People>();

var session = client.Driver.AsyncSession();
var res = await session.RunAsync(queryStr);
await res.FetchAsync();
    
foreach (var node in res.Current.Values["nodes"].As<List<INode>>())
{
    //Assumption of one label per node.
    switch(node.Labels.Single().ToLowerInvariant()){
        case "movie":
            movies.Add(new Movie(node));
            break;
        case "person":
            /* similar to above */
            break;
        default:
            throw new ArgumentOutOfRangeException("node",node.Labels.Single(),"Unknown node type");
    }
}

其中Movie等定义为:

public class Movie {
    public long Id {get;set;}
    public string Title {get;set;}
    
    public Movie(){}
    public Movie(INode node){
        Id = node.Id;
        Title = node.Properties["title"].As<string>();
    }
}

我需要研究如何解决客户端的不退回ID等问题,但这是达到目标的最快方法。

>