David A Stumpf
David A Stumpf

Reputation: 793

Neo4j v4 Driver Errors in .NET

My VB.NET code was working wonderfully using Imports Neo4j.v1 and Neo4j 3.x

I've upgraded to Neo4j 4.01 server on my laptop (Community Editon) and can connect and query successfully in Neo4j Desktop. I used NUGet to remove the old Neo4j reference and add Neo4j 4.01 driver. The code no longer works.

    Imports Neo4j.Driver
    Dim D = GraphDatabase.Driver(uri:=Neo4Lib.Neo4ConnectionString, authToken:=AuthTokens.Basic(Neo4Lib.Neo4UserName, Neo4Lib.Neo4Pswd))
    Using session = D.Session()
    'query database
    Dim rslt = session.run(CQ)
       .... processing ...
    End Using

It crashes are the Using session=D.Session() line with an error of

Overload resolution failed because no accessible 'Session' accepts this number of arguments.

I've studied the background materials at https://neo4j.com/docs/driver-manual/current/session-api/simple/ but cannot see the problem. I've had similar issues with Neo4j v4 on Azure with Python code.

Would appreciate suggested fixes.

Upvotes: 0

Views: 213

Answers (2)

Charlotte Skardon
Charlotte Skardon

Reputation: 6270

The original problem stems from the fact that the old code you were using had the Sync code in the Neo4j.Driver package, from 4.x onwards the Neo4j.Driver package contains only Async code.

There is a Neo4j.Driver.Simple package (https://www.nuget.org/packages/Neo4j.Driver.Simple/) which would act like the 1.7x versions did. As a quick side note - it's not possible to delete a package from Nuget - once it's been published it's always there - the 1.7.2 one is here: https://www.nuget.org/packages/Neo4j.Driver/1.7.2 - at the worst - it could be hidden - but in that case you would just have to ask for the version explicitly. So you shouldn't have to worry about keeping older versions around.

I've written 3 examples (below) which show using the new driver from VB from a selection of angles, using just the Neo4j.Driver package and using Neo4j.Driver.Simple package. All 3 of them need the following Import statements (and these are basic Console apps). Also - none of them need the ConfigBuilder parameter.

'The imports
Import System
Import Neo4j.Driver
Import System.Threading.Tasks

Neo4j.Driver.Simple version

As this is the closest to the 1.7.2 version - I'll put this first:

Sub Main
    SyncVersion()
End Sub

Sub SyncVersion()
    Dim query = "MATCH (m:Movie) RETURN m"

    'NB. Driver could be in a 'Using' on this.
    Dim driver = GraphDatabase.Driver(uri:="neo4j://localhost:7687", authToken:=AuthTokens.Basic("neo4j", "neo"))

    'Open the session
    Using session = driver.Session()
        Dim result As IResult = session.Run(query)
        For Each record As IRecord In result
            Console.WriteLine(record("m").Properties("title"))
        Next
    End Using

    'Close the driver
    driver.Dispose()
End Sub

The benefits of this are that it should closely match your codebase, with minimal changes for you.

Neo4j.Driver package - using Async

This route does need you to use Async / Await:

'Note - This is also declared as Async
Async Sub Main
    AsyncVersion()
End Sub

Async Function AsyncVersion() As Task
    Dim query = "MATCH (m:Movie) RETURN m"
    Dim driver = GraphDatabase.Driver(uri:="neo4j://localhost:7687", authToken:=AuthTokens.Basic("neo4j", "neo"))

    'Open the session
    Dim session = driver.AsyncSession()

    'Get the result cursor
    Dim result As IResultCursor = Await session.RunAsync(query)

    'Loop through it
    While Await result.FetchAsync()
        Console.WriteLine(result.Current("m").Properties("title"))
    End While

    'Close the session
    Await session.CloseAsync()
    'Close the driver
    Await driver.CloseAsync()
End Function

Downsides are that you have to control the lifecycle of the Session and Driver objects yourself - i.e. you can't just use a Using statement :/

Neo4j.Driver package - Async code in a Sync way

This is the worst case scenario, as it involves you basically sync-ifying async code, using .Wait() and some very clunky ForEaching - but I thought it would fill up the examples:

'Not Async this time
Sub Main
    SyncWithAsync()
End Sub

Sub SyncWithAsync()
    Dim query = "MATCH (m:Movie) RETURN m"
    Dim driver = GraphDatabase.Driver(uri:="neo4j://localhost:7687", authToken:=AuthTokens.Basic("neo4j", "neo"))

    'Open the session
    Dim session = driver.AsyncSession()

    'Get the result cursor
    Dim resultTask As Task(Of IResultCursor) = session.RunAsync(query)
    resultTask.Wait()

    'Loop through it, but as we're 'syncing' an async, we need to wait for 'fetch' to work.
    Dim fetchTask = resultTask.Result.FetchAsync()
    fetchTask.Wait()
    While fetchTask.Result
        Console.WriteLine(resultTask.Result.Current("m").Properties("title"))
        fetchTask = resultTask.Result.FetchAsync()
        fetchTask.Wait()
    End While

    'Close the session
    session.CloseAsync().Wait()

    'Close the driver
    driver.CloseAsync().Wait()
End Sub

You still have to manage the life cycle of the Session and Driver instances.

Hope that helps

Upvotes: 1

David A Stumpf
David A Stumpf

Reputation: 793

The solution: the session was run asynch and, as Hursey suggested above, it did require a ConfigBuilder argument, even though it was "Nothing". The return is different than my code for Neo4j 3.x, so I need to write new parsing code ... but I now have something to work with!

    Imports Neo4j.Driver

    CQ={neo4j cypher query}
    Dim D = GraphDatabase.Driver(uri:=Neo4Lib.Neo4ConnectionString, authToken:=AuthTokens.Basic(Neo4Lib.Neo4UserName, Neo4Lib.Neo4Pswd))
    Dim cb As ConfigBuilder = Nothing

    Using session = D.AsyncSession(cb)
     'query database
        Dim rslt As System.Threading.Tasks.Task = session.RunAsync(CQ)
              {process IResultCursor}
    End Using

Upvotes: 0

Related Questions