4

I have a Neo4j database which, for the sake of simplicity, contains User nodes and University nodes - where a User can be related to a University via the [:STUDENT_AT] relationship.

I want to return both the User details and the University details for a specific user, in this case querying by the 'username' value.

The query itself works fine, however I'm unable to work out the correct method for getting the deserialiser in Neo4jClient to give me the two objects to work with. Below is what I believe should work, but - alas - it does not.

graph.Cypher
    .Start("user", "node(*)")
    .Match("user-[:STUDENT_AT]->university")
    .Where<User>(user =>
        user.Username != null &&
        user.Username.ToLower() == username.ToLower())
    .Return((user, university) => new
    {
        User = user.As<User>(),
        University = university.As<University>()
    })
    .Results;

Where graph is an IGraphClient which has successfully connected to Neo4j.

The error I recieve is...

The query response contains columns User, University however <>f__AnonymousType0`2[[XYZ.Entities.User, XYZ.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[XYZ.Entities.University, XYZ.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] does not contain publically settable properties to receive this data.

So in summary, if anyone could provide me with a method of getting objects from a cypher query which returns multiple columns using Neo4jClient I would be extremely thankful!

Tom Davies
  • 899
  • 6
  • 20
  • stupid question perhaps, but could you have attributes in the university or user Neo4j nodes that do not exist (or at least not publicly) on your C# classes? – Kevin Versfeld Feb 15 '13 at 13:12
  • I thought that might be it as well... but trying just a simple query that returns just one type of node works fine. I would guess if there was some sort of problem mapping the attributes, this would throw an exception too. – Tom Davies Feb 15 '13 at 13:29

2 Answers2

2

The only way I was able to get it to work was to actually declare a type that was an aggregate of the multiple columns I needed. So for example, you would need to declare a dummy type that contains a User property and a University property. In your case you can try:

private class UserAndUniversity {
    public User User {get; set;}
    public University University {get; set;}
}

public object MyMethod()
{
    graph.Cypher
    .Start("user", "node(*)")
    .Match("user-[:STUDENT_AT]->university")
    .Where<User>(user =>
        user.Username != null &&
        user.Username.ToLower() == username.ToLower())
    .Return((user, university) => new UserAndUniversity
    {
        User = user.As<User>(),
        University = university.As<University>()
    })
    .Results;
}

Note that the property names in your dummy aggregate type are case sensitive; they must precisely match the names you use in your cypher RETURN clause.

This is clearly idiotic, but it was the only thing that worked for me; I tried everything from Tuples to the dynamic keyword.

ean5533
  • 8,884
  • 3
  • 40
  • 64
  • Thanks! Just tried this and it works great, but you're right it seems crazy that this is apparently the only way to get it to work :/ I would up-vote but my reputation isn't high enough. – Tom Davies Feb 16 '13 at 02:16
1

Anonymous types work from 1.0.0.514 onwards.

Upgrade, and the query shown in your question will work as written.

Tatham Oddie
  • 4,290
  • 19
  • 31