I'm having trouble retrieving matched relationships from a Cypher query.
I have this simple trial code:
var movie = client.Create(new Movie { Title = "The Matrix" });
client.Create(new Actor { Name = "Keanu Reeves" },
new ActedIn(movie, new ActedInPayload { Role = "Neo" }));
client.Create(new Actor { Name = "Hugo Weaving" },
new ActedIn(movie, new ActedInPayload { Role = "Agent Smith" }));
var actorsAndRoles = client
.Cypher
.Start(new { movie = movie })
.Match("actor-[r:ACTED_IN]->movie")
.Return((actor, r) => new
{
Actor = actor.As<Node<Actor>>()
// ActedIn = r.As<?????>()
})
.Results;
Problem is that I can't work out how to cast the r (with the matched relationship).
Tried various ".As" type casts, but none work. Casting to Relationship doesn't work because my relationship class doesn't have a parameterless constructor - but then the Relationship base class doesn't have a parameterless constructor itself, so don't think that would work. Casting to RelationshipReference on the other hand causes an exception. Not casting at all (just returning r) causes a "not supported" exception.
There are some related SO entries about this issue, but the suggested code there either no longer works or is deprecated.
How do I retrieve the matched relationship?
You can create a parameterless constructor for your relationship type, you just pass it 'duff' data, which I know sounds bad, but as you don't really need it, it won't hurt you:
public class ActedIn : Relationship<ActedInPayload>, IRelationshipAllowingSourceNode<Actor>, IRelationshipAllowingTargetNode<Movie>
{
public ActedIn() : base(-1, null) {}
public ActedIn(NodeReference targetNode, ActedInPayload data) : base(targetNode, data) {}
public override string RelationshipTypeKey
{
get { return "ACTED_IN"; }
}
}
So this is the ActedIn
class, with the parameterless constructor chaining a '-1' down to the base constructor.
Your query then becomes:
var actorsAndRoles = client
.Cypher
.Start(new {movie})
.Match("actor-[r:ACTED_IN]->movie")
.Return((actor, r) => new
{
Actor = actor.As<Node<Actor>>(),
ActedIn = r.As<RelationshipInstance<ActedInPayload>>()
})
.Results;
Note, it's being cast to a RelationshipInstance
of type ActedInPayload
not ActedIn
, then, to get the data you might want:
foreach (var actorsAndRole in actorsAndRoles)
{
Console.WriteLine("{0} acted as {1} - which is in the db as {2}-[ACTED_IN]->{3}",
actorsAndRole.Actor.Data.Name,
actorsAndRole.ActedIn.Data.Role,
actorsAndRole.ActedIn.StartNodeReference.Id,
actorsAndRole.ActedIn.EndNodeReference.Id);
}
Which will give you something like:
Keanu Reeves acted as Neo - which is in the db as 482-[ACTED_IN]->481
Hugo Weaving acted as Agent Smith - which is in the db as 483-[ACTED_IN]->481
Though obviously with different numbers on your own DB.