0
votes

I have a method that performs a Cypher query that I would like return all nodes and their names that have a relationship with a node specified(64) in the query:

start n = node(64) match (n)--(x) return x.Name;

Now when I try and do this in my code it does not want to work. Here is my method:

public string GetAllFirstLevelRelatives(long NodeId)
{

    string QueryResult = null;

    try
    {
        var query = client_connection
            .Cypher
            .Start(NodeId, client_connection.RootNode)
            .Match(NodeId, "--(x)")
            .Return<Node<GraphNode>>("(x).name");

        QueryResult = query.Results.ToString();
    }
    catch (Exception e)
    {

    }
    return QueryResult;
}

I would like this query to return the names.

Could anyone help me please?

1

1 Answers

7
votes

This query:

start n = node(64) match n--x return x.Name;

Should be written in C# as:

var query = graphClient
    .Cypher
    .Start("n", node)           // START n=node(123)
    .Match("n--x")              // MATCH n--x
    .Return<string>("x.Name");  // RETURN x.Name

There were a few problems with the sample code you provided:

  1. There will likely be multiple nodes, but your method was only returning a single string result. Calling Results.ToString() is going to return something like "System.Collections.IEnumberable<string>" instead of the actual results.
  2. You should avoid passing node ids around as longs. Doing so encourages you to use the raw numbers, which you shouldn't be doing. Instead, use NodeReference. Any query that you run with Neo4jClient will give you a NodeReference object back. Use this to run your next query. To start your very first query, we supply IGraphClient.RootNode. You basically never need to touch node ids.
  3. Wrapping any .NET code in a try {} catch {} block where the catch section is empty is always a big no-no. Please do not write this in any code, ever. :)
  4. x.Name is likely a string, but then you were calling this with .Return<Node<GraphNode>>. This basically says "load x.Name (a string) but give it back to me as a Node<GraphNode>". That doesn't make a lot of sense. You need to match the types.

Combining the query I wrote above, and those points, this is what your method should look like:

public IEnumerable<string> GetAllFirstLevelRelatives(NodeReference node)
{
    var query = graphClient
        .Cypher
        .Start("n", node)           // START n=node(123)
        .Match("n--x")              // MATCH n--x
        .Return<string>("x.name");  // RETURN x.name

    return query.Results.ToList();
}

To improve this further, you should take advantage of our type system. What is "x" in your query? Let's imagine it's a movie.

You should create a class that describes what a movie node contains:

public class Movie
{
    public string Name { get; set; }
}

That class should be a 'POCO' (plain old class object) which means it should only have basic properties on it, and not methods or logic.

Then, use this type information in your query:

public IEnumerable<Movie> GetAllRelatedMovies(NodeReference node)
{
    var query = graphClient
        .Cypher
        .Start("n", node)
        .Match("n--movie")
        .Return<Movie>("movie");

    return query.Results.ToList();
}

Now you have a list of movies, instead of just a list of strings. It's quite unlikely that you'd just want the name of the movies, so this way you get access to all of the properties.