Neo4j 二:使用C#更新和查询Neo4j

本文使用的IDE是Visual Studio 2015 ,驱动程序是Neo4j官方的最新版本:Neo4j Driver 1.3.0 ,创建的类库工程(Project)要求安装 .NET Framework 4.6版本,Neo4j官方提供的驱动程序使用起来非常简单,非常依赖于Cypher语言,但是,官方驱动程序仅支持标量类型的参数(Parameters),由于Neo4j的批量更新,例如,Cypher语言的foreach,unwind命令等用于批量操作,非常依赖于参数,这也成了官方驱动最大的缺点。

一,安装Neo4j Driver 1.3.0

1,依赖.NET Framework 4.6版本

创建Neo4jProviders工程,设置工程的目标架构(Target Framework)为.NET Framework 4.6

2,安装驱动Neo4j Driver 1.3.0

点击工具(Tools)菜单,通过NuGet Package Manager的控制台命令安装Neo4j的.Net驱动程序

PM> Install-Package Neo4j.Driver

二,驱动程序主要方法和对象

Neo4j驱动程序十分简单,主要有Driver对象,Session对象和Transaction对象。Driver对象用于连接数据库,Session对象用于创建事务,事务对象用于执行Cypher查询。事务只能在Read或Write模式下执行,由于Driver对象不会解析Cypher查询,它也不会检测到事务执行的是写,还是读操作,因此,当一个写模式事务执行的是读操作,Neo4j数据库会抛出错误,执行失败。

Note that the driver does not parse Cypher and cannot determine whether a transaction is intended to carry out read or write operations. As a result of this, a write transaction tagged for read will be sent to a read server, but will fail on execution.

1,连接数据库

Neo4j通过Driver来连接图形数据库,需要输入身份验证信息:Host(Bolt监听地址,例如”bolt://host:7687“),用户名和密码。

复制代码
private readonly IDriver Driver;

public HelloWorldExample(string uri, string user, string password)
{
    Driver = GraphDatabase.Driver(uri, AuthTokens.Basic(user, password));
}
复制代码

2,创建会话(Session)

会话是一系列事务(Transaction)的容器,用于连接图形数据库,并创建事务执行的上下文。示例代码创建Session之后,以自动提交模式执行事务,在数据库中创建一个节点,该节点具有标签和属性。

在Neo4j的驱动中,发送到Neo4j引擎的Cypher查询语句包含两部分:Query和Parameters,其中,Query是在数据库中执行的Cypher语句,Parameters是传递引擎的参数,在Query中以$param引用参数。

复制代码
public void AddPerson(string name)
{
    using (var session = Driver.Session())
    {
        session.Run("CREATE (a:Person {name: $name})", new {name});
    }
}
复制代码

3,创建事务

在Neo4j的事务中,读写操作都必须处于事务的上下文中。在Session对象中,当事务以自动提交模式执行(通过session.Run()函数调用)时,事务只包含一个Cypher语句,但是,这种模式有一个缺点,当Cypher语句执行失败时,事务不能重新执行(Replay)。Neo4j推荐使用事务函数模式,在Session中调用WriteTransaction()或 ReadTransaction()函数,并在事务函数包含事务单元,在事务执行失败时,能够在异常处理代码中重新执行Cypher语句。

复制代码
public void AddPerson(string name)
{
    using (var session = Driver.Session())
    {
        session.WriteTransaction(tx => tx.Run("CREATE (a:Person {name: $name})", new {name}));
    }
}
复制代码

三,参数化查询

Cypher支持参数化查询,在Cypher语句中,使用参数替代表达式,实体的ID,参数不能用于关系类型和标签。在Neo4j数据库中,参数能够优化查询,使得Cypher的执行计划更容易被缓存,查询更快速。在Cypher中,通过$param引用参数。

1,使用参数创建节点

在执行事务之后,Session返回数据库执行的结果,通过result.Summary查看Cypher语句执行的结果。

复制代码
public bool CreateSingleNode(string lable,string name)
{
    string query = string.Format("CREATE (n:{0} ", lable)+ @"{name: $name})";
    using (var session = Driver.Session(AccessMode.Write))
    {
        var result = session.WriteTransaction(tx=>tx.Run(query, new { name }));
        IResultSummary rs = result.Summary;
        return rs.Counters.NodesCreated == 1;
    }
}
复制代码

2,使用参数创建关系

通过new创建匿名类型,参数名是匿名类型的字段,字段名必须和Cypher语句中的参数($para)保持一致。

复制代码
public bool CreateRelationship(string RelationshipType,string SourceNodeName,string TargetNodeName)
{
    string query = string.Format(@"match (n),(m) where n.name=$source and m.name=$target create (n)-[:{0}]->(m);",RelationshipType);

    using (var session = Driver.Session())
    {
        var result = session.WriteTransaction(tx => tx.Run(query,new {source=SourceNodeName,target= TargetNodeName } ));
        IResultSummary rs = result.Summary;
        return rs.Counters.RelationshipsCreated == 1;
    }
}
复制代码

四,查询数据库

向Neo4j数据库发送请求,返回的是数据结构是一个表格,Title是return子句的投影的字段。

如示例图所示,查询返回的结构是表格(行-列)式的,列值主要分为两种,要么是节点的属性列表,以JSON结构显示,要么是标量值。

驱动程序的Session返回查询的结果,Keys字段是Cypher语句中return子句投影的字段列表;Values字段返回是查询结果。

复制代码
public void MatchNodes(string lable, string name)
{
    string query = string.Format(@"MATCH (n:{0} ", lable)+ @"{name: $name})-[r]->(m) RETURN n,id(n);";
    using (var session = Driver.Session(AccessMode.Read))
    {
        var result = session.ReadTransaction(rx => rx.Run(query, new { name }));
        //return 子句投影的字段列表
        IReadOnlyList<string> keys = result.Keys;
        //查询返回的数据行
        var rows = result.ToList();
        foreach(var row in rows)
        {
            //每个数据行都包含多个数据列
            var columns = row.Values;
            foreach (var column in columns)
            {
                //每个数据列,可能是一个节点,也可能是一个标量值
                if(column.Key=="n")
                {
                    var node = column.Value as INode;

                    long NodeID = node.Id;
                    string NodeLables = string.Join(",", node.Labels.ToArray());
                    foreach (var property in node.Properties)
                    {
                        string Property=string.Format("Property[Key:{0},Value:{1}", property.Key, property.Value);
                    }
                }
                        
                if(column.Key=="id(n)")
                {
                    long NodeID=long.Parse(column.Value.ToString());
                }
            }
        }       
    }
}
复制代码

Leave a Reply

Your email address will not be published. Required fields are marked *