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.