Introduction
ExRam.Gremlinq is a .NET object-graph-mapper (OGM) for Apache TinkerPop™ enabled databases. An OGM is for the realm of graph-databases what, among others, Entity Framework or NHibernate (generally called object-relational-mappers, or ORMs) are for relational databases.
TinkerPop-enabled graph databases are queried by a graph query language called Gremlin. ExRam.Gremlinq enables .NET developers to create and issue this kind of queries in a strongly-typed fashion by using the powerful Gremlinq-DSL abstraction over their own model of domain entity classes (usually called POCOs). It will serialize the query to valid Gremlin for execution on the server and deserialize the results to the correct .NET types.
Features
Type safety
ExRam.Gremlinq queries carry and pass on full information about the query result type and its role (vertex, edge, scalar etc.). This minimizes the possibility of writing and executing invalid queries, speeding up development.
Example
For a simple example, let's assume the domain of a simple pet-shop with classes Cat
and
Dog
that both inherit from an abstract base class Animal
. A plain Gremlin-query asking for all
Cats in the database named 'Poppy' would look like this:
ExRam.Gremlinq allows for issuing this query using type-safe C# language constructs over the Cat
-class:
At every step in the query, ExRam.Gremlinq is aware that it is dealing with vertices of type
Cat
and, upon retrieval of results from the server, deseriailze these into instances of type Cat
.
Graph model
ExRam.Gremlinq efficiently manages the type hierarchy of Plain Old CLR Objects (POCOs), offering extensive customization options. Users can tailor member names, adjust type name to label mappings, and easily ignore specific type members. This flexibility ensures seamless integration with database schemas and simplifies data model management.
Powerful DSL
The type system of ExRam.Gremlinq itself, represented as various fluent interfaces that carry result type information, enables developers to rapidly write correct queries.
Example
Again assuming the above domain, enriched with SoldTo
and Customer
classes that represent
edges labelled SoldTo
pointing from Animals
to Customers
, we can query for the customer that
bought a cat named 'Poppy':
var cat = await g
.V<Cat>()
.Where(cat => cat.Name == "Poppy")
.Out<SoldTo>()
.OfType<Customer>()
.FirstOfDefaultAsync()
The ExRam.Gremlinq DSL will only allow fluently using the Out<...>
method if it knows that it's
currently on a vertex. This avoids accidentally trying to walk edges from e.g. edges or scalar values.
The Gremlin language by itself does not prohibit writing such queries, so that bugs could only
be detected during integration tests or, even worse, in production.
C# expression recognition
ExRam.Gremlinq is capable of recognizing a wide range of C#-expressions and generate valid Gremlin. This enables developers to focus on the business logic in the language they're comfortable with, instead of dealing directly with the intricacies of the Gremlin query language.
Simple example
Querying for all the Cats whose name starts with the letter "B". Switch the tab to see the according translation into Gremlin.
More complex example
Here's a more complex example showing the power of ExRam.Gremlinq in recognizing expressions that contain an ordinary LINQ method as well as a reference to a step labels created earlier in the query.
Inherent thread safety
In ExRam.Gremlinq, the design prioritizes thread safety and purity throughout query execution. All queries and environment structures are immutable, meaning they cannot be modified once created. This inherent immutability ensures that multiple threads can safely access and operate on these structures concurrently without the risk of unintended changes or data corruption. Additionally, leading up to actual query execution, methods on the Gremlinq interface are considered pure, devoid of side effects. This purity guarantees that invoking these methods won't alter the state of the system, further reinforcing the reliability and predictability of ExRam.Gremlinq in multi-threaded environments.
Customization
ExRam.Gremlinq excels in customization, providing developers control over query serialization, execution, and result deserialization. Custom scalar type registration ensures accurate data integration with native graph types, while query execution interception allows for fine-tuning and optimization. This flexibility enables seamless adaptation to project needs, enhancing efficiency in graph database operations.
Support for Bytecode and Groovy queries
ExRam.Gremlinq supports both Bytecode queries (for AWS Neptune, etc.) and Groovy scripts (the sole format supported by Azure CosmosDB). Developers can effortlessly utilize either format without worrying about compatibility, ensuring smooth operation across different database environments.
ASP.NET integration
Separate NuGet packages seamlessly allow registering ExRam.Gremlinq services with ASP.NET so they are available via dependency injection in ASP.NET middleware and controllers.
Provider support
ExRam.Gremlinq comes with out-of-the-box support for
Other providers may just work with the generic Gremlin Server-package, be provided by the community or be part of the commercial extension package.