Search code examples
foreachneo4jcypherneo4jclientcomplextype

Automatically add relationships for complex types


I'm looking to do bulk importing of complex models containing objects and collections into Neo4j.

I have the following model:

public class PSNGame
{
    public int EarnedPlatinum { get; set; }
    public int EarnedGold { get; set; }
    public int EarnedSilver { get; set; }
    public int EarnedBronze { get; set; }
    public int EarnedTotal { get; set; }
    public int AvailablePlatinum { get; set; }
    public int AvailableGold { get; set; }
    public int AvailableSilver { get; set; }
    public int AvailableBronze { get; set; }
    public int AvailableTotal { get; set; }
    public double PercentCompleteBronze { get; set; }
    public double PercentCompleteSilver { get; set; }
    public double PercentCompleteGold { get; set; }
    public double PercentCompletePlatinum { get; set; }
    public double PercentCompleteTotal { get; set; }
    public DateTimeOffset LastUpdated { get; set; }
    public string Platform { get; set; }
    public string NPCOMMID { get; set; }
    public string TitleName { get; set; }
    public string TitleDetail { get; set; }
    public string Image { get; set; }
    public string LargeImage { get; set; }
    // complex model parts
    public GameInfo GameInfo { get; set; }
    public GameCommon.Rating Rating { get; set; }
    public IEnumerable<GameCommon.RatingDescriptor> RatingDescriptors { get; set; }
    public IEnumerable<GameCommon.Genre> Genres { get; set; }
    public IEnumerable<GameCommon.Publisher> Publishers { get; set; }
    public IEnumerable<GameCommon.Developer> Developers { get; set; }

    public PSNGame()
    {

    }
}

I use this code to insert the games to Neo4j, however, it only works without the complex objects/collections:

var client = new GraphClient(new Uri("http://localhost:7474/db/data"));
client.Connect();
client.Cypher
    .Match("(p:PSNProfile {PSNId : {profile}.PSNId})")
    .ForEach(@"(game in {PSNGames} | 
                MERGE p-[:PLAYS {LastPlayed : game.LastUpdated}]->(g:PSNGame {NPCOMMID : game.NPCOMMID})-[:LOCALE]->(l:PSNGameLocalized {NPCOMMID : game.NPCOMMID}) 
                SET g = game, 
                    l = { NPCOMMID : game.NPCOMMID, 
                         TitleName : game.TitleName, 
                       TitleDetail : game.TitleDetail, 
                            Locale : {locale} 
                        })")
    .WithParams(new
    {
        PSNGames = games.ToList(),
        locale = locale,
        profile = profile
    })
    .ExecuteWithoutResults();

I've tried doing nested FOREACH clauses, but this can get messy very fast. Also, the syntax of MERGE g-[:GAME_RATING]->g.Rating doesn't seem quite right and Neo4j complains that there is an invalid . token. My thought was to loop over the collections and access specific properties with the . accessor, but it doesn't look like Cypher likes the syntax.

For complex types, I would like to automatically create/update relationships/nodes for any child objects/collections contained in the complex type. Is there a way to do this in Neo4jClient?


Solution

  • Is there a way to do this in Neo4jClient?

    No. Neo4jClient is a lower level driver, kind of like SqlClient. If you want more ORM-style behaviours on top of it, that would be a higher level library, equivalent to something like Entity Framework. There was a project called Neo4jRepository for a while, which built on top of Neo4jClient, but it has not been updated for the Neo4j 2.0 wave as far as I'm aware.