Reputation: 960
Let's start with an example data set. There are 2 nodes and 2 relationships with differing relationship types between them. Both nodes and relationships have properties. Don't focus too much on the semantics, this is derived from a use case I cannot show here directly.
create (a:AlphaNode {name: "Alice"} )
create (b:BetaNode {name: "Bob"} )
create (a)-[:HAS {really: false} ]->(b)
create (a)-[:NEEDS {timespan: 42} ]->(b)
Now, I would like to run a query along the following lines:
match (a:AlphaNode)-[r:HAS|NEEDS]->(b:BetaNode)
// where etc ... (not important in the example)
return a, r, b
This will return 2 result sets, where the nodes are identical, only the relationship denoted by r
will differ between the result sets.
My C# code using Neo4jClient should look like this:
client.Cypher
.Match("(a:AlphaNode)-[r:HAS|NEEDS]->(b:BetaNode)")
.ReturnDistinct((a, r, b) => new
{
A = a.As<AlphaNode>(),
R = r.As<SomeRelationship>(),
B = b.As<BetaNode>()
})
// .ResultAsync etc. (not important, here)
;
Now, I'm running into problems with SomeRelationship
. Surely, I could make it a POCO/DTO, but then I wouldn't have access to the relationship type (HAS
or NEEDS
). I can't find a good hint or example in the docs and all I've found are hints towards the classes Relationship
, RelationshipInstance
, RelationshipReference
(which would have a relationship type, but this is not read from the database, but rather fixed by class inheritance), but I can't really make them (or their descendants, to be more precise) work like this (even for a single relationship, but the dynamics are the actual point, here).
Is there a way to do this more cleanly with a dynamic relationship POCO than with some weird inheritance that is mainly there in order to replace a constructor with a parameterless one? I think the intentions for these classes are a bit different from what I expect. Don't get me wrong, I'd love to inherit a relationship-ish base class, but the base class would have to provide the relationship type from the response and have a parameterless constructor in the first place.
Upvotes: 0
Views: 47
Reputation: 846
I'll throw an answer out there because I ran into a similar problem that you have. I have a couple of solutions depending on what you need.
This method requires you to modify the returned anonymous object to accommodate all of the relationship properties in a Dictionary<string, string>
and the type of relationship as a string
.
client.Cypher
.Match("(a:AlphaNode)-[r:HAS|NEEDS]->(b:BetaNode)")
.ReturnDistinct((a, r, b) => new
{
A = a.As<AlphaNode>(),
RelationshipProperties = r.CollectAs<Dictionary<string, string>>(),
RelationshipType = r.Type(),
B = b.As<BetaNode>()
}).ResultsAsync;
Likely overkill for your situation, but for my use-case it was necessary. You can return the entire path (both nodes and the relationship) as a JSON string by using the following query. Then, you can serialize it into your models however you want.
client.Cypher
.Match("path = (a:AlphaNode)-[r:HAS|NEEDS]->(b:BetaNode)")
.Return<string>("path")
.ResultsAsync;
Upvotes: 0