Reputation: 427
I am using the Neo4j .Net client to interface with a Neo4j database.
I often come by this issue when trying to map related nodes to nested classes :
For example mapping
(:Foo)-[:FOOBAR]->(:Bar)
to the form
public class Foo {
public string FooPropOne { get; set; }
public string FooPropTwo { get; set; }
public List<Bar> Bars { get; set; }
}
public class Bar {
public string BarPropOne { get; set; }
public string BarPropTwo { get; set; }
}
To get the correct output for deserialzation I have to write the query like so:
Foo foo = WebApiConfig.GraphClient.Cypher
.Match("(f:Foo)-[:FOOBAR]->(b:Bar)")
.With("@{
FooPropOne: f.FooPropOne,
FooPropTwo: f.FooPropTwo,
Bars: collect(b)
} AS Result")
.Return<Foo>("Result")
.SingleOrDefault();
To a certain extent this is fine, and works perfectly, but becomes quite unwieldy the more properties the Foo class has.
I was wondering if there was something I can do in the "With" statement to add a temporary property (in the above case "Bars") when returning the nodes, that does not require me to write every single property on the parent node?
Something like
.With("f.Bars = collect(b)")
.Return<Foo>("f")
that wont actually affect the data stored in the DB?
Thanks in advance for any relpies!!
Upvotes: 1
Views: 688
Reputation: 6280
I don't know of a way to add a temporary property like you want, personally - I would take one of two approaches, and the decision really comes down to what you like to do.
The choosing properties version
var foo = client.Cypher
.Match("(f:Foo)-[:FOOBAR]->(b:Bar)")
.With("f, collect(b) as bars")
.Return((f, bars) => new Foo
{
FooPropOne = f.As<Foo>().FooPropOne,
FooPropTwo = f.As<Foo>().FooPropTwo,
Bars = Return.As<List<Bar>>("bars")
}).Results.SingleOrDefault();
This version allows you to be Type Safe with your objects you're bringing out, which on a class with lots of properties does limit the chance of a typo creeping in. This will give you back a Foo
instance, so no need to do any other processing.
The little bit of post-processing required version
var notQuiteFoo = client.Cypher
.Match("(f:Foo)-[:FOOBAR]->(b:Bar)")
.With("f, collect(b) as bars")
.Return((f, bars) => new
{
Foo = f.As<Foo>(),
Bars = bars.As<List<Bar>>()
}).Results;
This saves on the typing out of the properties, so in a big class, a time saver, and also means if you add extra properties you don't need to remember to update the query. However you do need to do some post-query processing, something like:
IEnumerable<Foo> foos = notQuiteFoo.Results.Select(r => {r.Foo.Bars = r.Bars; return r.Foo;});
Personally - I like Option 2 as it has less potential for Typos, though I appreciate neither is exactly what you're after.
Upvotes: 2