Gremlinq / ExRam.Gremlinq

A .NET object-graph-mapper for Apache TinkerPop™ Gremlin enabled databases.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Creating Vertex with Guid property fails using JanusGraph

ManfredLange opened this issue · comments

Describe the bug
Creation of Vertex with Guid property fails using JanusGraph

Expected behavior
A vertex having a property of type Guid should not fail upon creation but should be supported since Newtonsoft.Json can serialize and deserialize objects with property Guid without a problem.

If it cannot be supported out of the box, Gremlinq should make it easy to configure custom serializers/deserializers to handle types like Guid without code duplication or introduction of addtional model classes which can be consumed by the graph database.

Version information
Gremlinq version: 8.5.0

Minimal working example
Minimal repro repo can be found at https://github.com/ManfredLange/gremlinq-tests

Repro is a console app with the following:

  • Three domain classes (Vertex, Edge, Person)
  • Method to connect to local JanusGraph server
  • Code to create one vertex and then to retrieve all vertices labelled Person

You need a JanusGraph server. If you don't have one, you can use their Docker image. Run these commands:

docker pull janusgraph/janusgraph
docker run -it -p 8182:8182 janusgraph/janusgraph

The README.md of the repro repo contains these instructions as well. I don't know how to strip the example further down at this point.

Additional context

Gremlinq offers the extension methods ConfigureSerializer and ConfigureDeserializer. I checked this repo as well as the samples repo but none of the examples there appear to work in my context.

I think that either Guid can be supported out of the box -or- there should to be a generic way to configure serialization/deserialization such that code for converting Guid from/to string is not duplicated for each vertex or edge property.

Gremlinq has the unique opportunity to avoid having yet another model for the mere purpose of accommodating constraints of the database. One of the reasons to prefer a graph database over a relational system is being able to avoid this additional model. ORMs in the relational world may require this. I see Gremlinq as roughly the graph equivalent to a relational ORM. (You could say it is a OGM or Object Graph Mapper, if you like).

Note: In my opinion using string instead of Guid is not an option as Guid is conceptually a different type. C# and .NET in general use a strong type system. It'd be a shame to dilute this advantage. This may, however, be a matter of my personal preference.

My background is mostlly from an (Fluent) NHibernate perspective. In that context it's typically a mapping that can be customized. I was hoping that configuring serializers/deserializers was the equivalent with Gremlinq. Perhaps more examples around this could be helpful.

According to https://www.json.org/json-en.html and https://json-schema.org/understanding-json-schema/reference/type.html DateTime is not a primitive JSON data type either. Interestingly, though, a Vertex with a property type of DateTime works just fine while a Vertex with a property type Guid fails. Why are these two treated differently? Both are value types.

Your repro code is almost there. Custom serialization looks good (haven't run it yet). For deserialization, you don't specify the type you want, but the type you have - e.g. JToken. So this won't ever be called, but it's almost there.

Not really examples, but the actual standard deserializers are configured here. Should be straightforward to go from there.

Once you fixed deserialization in your repro, let me know how it works for you.

Thank you, Daniel.

Not really examples, but the actual standard deserializers are configured here. Should be straightforward to go from there.

I used the DateTime deserialization code as a "template" and added to the repro repo what I believe to be the equivalent for Guid. See https://github.com/ManfredLange/gremlinq-tests/blob/e469eafb63265558c74907c28e544ef40dfb0478/Program.cs#L56

However, that deserialization configuration code is never hit. Looks as if I am still missing a piece of information or a piece of insight.

Happy to dig a bit deeper. Would you mind pointing me in the right direction?

(As a suggestion: It might be beneficial to use perma links when referring to lines in source code on github. I pushed another commit and the link in your post to the line in my code is now off by at least a dozen lines. This makes it harder if not impossible for others to follow this conversation. Just a thought. Entirely your choice, of course.)

Custom (de)serializers must come after any Use(ProviderXYZ, JanusGraph in your case), otherwise the deserializer won't be overridden.

I've changed the sequence as suggested with the UseJanusGraph() first and the (de)serializer configs after that, see https://github.com/ManfredLange/gremlinq-tests/blob/1f2cd3bcb3459eb1aa1a63dbf593ebb4f8ca27be/Program.cs#L52

It now hits the override in line 67, see https://github.com/ManfredLange/gremlinq-tests/blob/1f2cd3bcb3459eb1aa1a63dbf593ebb4f8ca27be/Program.cs#L67

However, the deserializer is never called with a value type of Guid. It's called for other types, though.

So, I still observe the same exception. What am I missing?

Turns out the actual solution is even simpler.

@danielcweber Awesome! That did the trick. I just approved and merged your pull request. I'll clean up my example, then post a link to that repository here and close the issue. Thank you for your help and keep up the good work!

This isssue has now been resolved. An example demonstrating how to configure ExRam.Gremlinq to support properties of type Guid can be found here.