Question

After some struggle to get it right I manage to save relationships with properties to a Neo4j db with Neo4jClient. The problem arrises when I want to read those relationships back. Suddenly the query which worked like a charm before does not return my users anymore? No exceptions are thrown, the call just silently returns empty :( I read about possible deserializing problems and added the parameterless constructor to the relationship class but no luck.

public class UserHasHomeCity : Relationship<HasHomeCity>, IRelationshipAllowingSourceNode<UserEntity>, IRelationshipAllowingTargetNode<CityEntity>
{
    public UserHasHomeCity()
        : base(-1, null)
    {
    }

    public UserHasHomeCity(NodeReference targetNode, HasHomeCity data)
        : base(targetNode, data)
    {
    }

    public const string TypeKey = "USER_HAS_HOME_CITY";
    public override string RelationshipTypeKey
    {
        get { return TypeKey; }
    }
}

public class HasHomeCity
{
    public string Date { get; set; }

    public HasHomeCity()
    { }

    public HasHomeCity(string date)
    {
        this.Date = date;
    }
}

And here is my query:

     var graphResults = graphClient.Cypher
            .Match("(user:User)-[:USER_IS_IN_ROLE]-(role:Role)",
            "(user:User)-[:USER_HAS_HOME_CITY]-(homeCity:City)-[:CITY_IS_IN_COUNTRY]-(homeCountry:Country)",
            "(user:User)-[:USER_HAS_LIVING_CITY]-(livingCity:City)-[:CITY_IS_IN_COUNTRY]-(livingCountry:Country)")
            .Where((UserEntity user) => user.Id == id)
            .Return((user, role, homeCity, livingCity, homeCountry, livingCountry) => new
            {
                User = user.As<UserEntity>(),
                Roles = role.CollectAs<RoleEntity>(),
                HomeCity = homeCity.As<CityEntity>(),
                LivingCity = livingCity.As<CityEntity>(),
                HomeCountry = homeCountry.As<CountryEntity>(),
                LivingCountry = livingCountry.As<CountryEntity>()
            }).Results;
Was it helpful?

Solution

Neo4jClient is moving away from using Relationship and Node classes where possible, so, the good news is - you don't need to define your relationships as : Relationship any more! In fact, depending on how far you want to take it, you don't even need your UserHasHomeCity class at all!

Relationship properties are treated the same as nodes, in the sense that they are just POCO objects.

So, to create (as I'm sure you know) we do something like:

var userData = new User {Id = "Id-1"};
var cityData = new City {Name = "Brighton"};
var countryData = new Country {Name = "UK"};
var userHasHomeData = new HasHomeCity {Date = "April 1980"};
var generalData = new CountryRelationshipData { Area = "South Coast" };

gc.Cypher
    .Create("(country:Country {countryParams})")
    .WithParam("countryParams", countryData)
    .ExecuteWithoutResults();

gc.Cypher
    .Match("(country:Country)")
    .Where((Country country) => country.Name == "UK")
    .CreateUnique("(city:City {cityParams})-[:CITY_IS_IN_COUNTRY {relParams}]->(country)")
    .WithParam("cityParams", cityData)
    .WithParam("relParams", generalData)
    .ExecuteWithoutResults();

gc.Cypher
    .Match("(city:City)")
    .Where((City city) => city.Name == "Brighton")
    .Create("(user:User {userParams})-[:USER_HAS_HOME_CITY {relParams}]->(city)")
    .WithParam("userParams", userData)
    .WithParam("relParams", userHasHomeData )
    .ExecuteWithoutResults();

which will give us a (User)-[:USER_HAS_HOME_CITY]-(City) structure.

To retrieve the relationship properties, we can use this query:

var query = gc.Cypher
    .Match("(user:User)-[r:USER_HAS_HOME_CITY]-(city:City)-[r1:CITY_IS_IN_COUNTRY]-(country:Country)")
    .Where((User user) => user.Id == "Id-1")
    .Return((user, city, r, country, r1) =>
        new
        {
            User = user.As<User>(),
            City = city.As<City>(),
            HasHome = r.As<HasHomeCity>(),
            Country = country.As<Country>(),
            CountryRel = r1.As<CountryRelationshipData>()
        });

and looping through the results (all 1 of them in this case):

var res = query.Results.ToList();
foreach (var result in res)
    Console.WriteLine("User ({0}) home city: {1} (which is in {2}, {3}) since {4}", result.User.Id, result.City.Name,result.CountryRel.Area,  result.Country.Name, result.HasHome.Date );

will give us:

User (Id-1) home city: Brighton (which is in South Coast, UK) since April 1980

as the output.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top