Skip to content

savasp/graphmodel-dotnet

GraphModel

License .NET GitHub release Build Status Coverage Codecov CodeQL Neo4j Compatibility Contributors Issues Stars

A powerful, type-safe .NET library ecosystem for working with graph data structures and graph databases. GraphModel provides a clean abstraction layer over graph databases with advanced LINQ querying, transaction management, and relationship traversal capabilities.

πŸš€ Features

  • πŸ”’ Type-Safe Graph Operations - Work with strongly-typed nodes and relationships using modern C# features
  • πŸ” Advanced LINQ Support - Query your graph using familiar LINQ syntax with graph-specific extensions
  • πŸ”„ Graph Traversal & Path Finding - Navigate complex relationships with depth control and direction constraints
  • ⚑ Transaction Management - Full ACID transaction support with async/await patterns
  • 🎯 Provider Architecture - Clean abstraction supporting multiple graph database backends
  • πŸ“Š Neo4j Integration - Complete Neo4j implementation with LINQ-to-Cypher translation
  • πŸ›‘οΈ Compile-Time Validation - Code analyzers ensure that the data model requirements
  • πŸ—οΈ Complex Object Serialization - Automatic handling of complex properties and circular references
  • πŸ“ˆ Build-time code generation - Automatic code generation for efficient serialization/deserialization of domain data types
  • 🎨 Attribute-Based Configuration - Configure nodes and relationships using intuitive attributes

πŸ“¦ Packages

To get started, you only need to install the Neo4j provider package:

Package Description NuGet
Cvoya.Graph.Model.Neo4j Neo4j provider implementation (required) NuGet
Cvoya.Graph.Model Core abstractions and interfaces NuGet
Cvoya.Graph.Model.Analyzers Compile-time code analyzers (optional, recommended) NuGet
Cvoya.Graph.Model.Serialization.CodeGen Compile-time code generation NuGet
Cvoya.Graph.Model.Serialization Serialization-related functionality NuGet

πŸƒβ€β™‚οΈ Quick Start

1. Installation

# Install the Neo4j provider (required)
dotnet add package Cvoya.Graph.Model.Neo4j

# Optionally, add code analyzers for extra compile-time validation (recommended)
dotnet add package Cvoya.Graph.Model.Analyzers

2. Define Your Domain Model

using Cvoya.Graph.Model;

[Node("Person")]
public class Person : INode
{
    public string Id { get; set; } = Guid.NewGuid().ToString();

    [Property("first_name", Index = true)]
    public string FirstName { get; set; } = string.Empty;

    [Property("last_name", Index = true)]
    public string LastName { get; set; } = string.Empty;

    // The Property attribute is optional
    public int Age { get; set; }
    public Address? HomeAddress { get; set; } // Complex types supported
}

// When used as the type of a property, it makes that property a "complex property"
public class Address
{
    public string Street { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
    public Point? Coordinates { get; set; } // Spatial data
}

[Relationship("KNOWS")]
public class Knows : IRelationship
{
    public string Id { get; set; } = Guid.NewGuid().ToString();
    public string StartNodeId { get; set; } = string.Empty;
    public string EndNodeId { get; set; } = string.Empty;
    public RelationshipDirection Direction { get; init; } = RelationshipDirection.Outgoing;

    public DateTime Since { get; set; }

    // Relationships cannot have complex properties
}

For your convenience, the Cvoya.Graph.Model package also offers Node and Relationship records so that you only have to focus on your domain-specific properties:

public record Person : Node
{
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public int Age { get; set; }
    public Address? HomeAddress { get; set; }
}

public record Knows : Relationship
{
    public DateTime Since { get; set; }
}

// or

public record Knows : Relationship
{
    public Knows() : base(Guid.NewGuid().ToString("N"), Guid.NewGuid().ToString("N")) { }
    public Knows(Person p1, Person p2) : base(p1.Id, p2.Id) {}

    public DateTime Since { get; set; }
}

3. Create Graph Instance

using Cvoya.Graph.Model.Neo4j;

// Neo4j provider
var store = new Neo4jGraphStore(
    uri: "bolt://localhost:7687",
    username: "neo4j",
    password: "password",
    databaseName: "myapp"
);
var graph = store.Graph;

4. Basic Operations

// Create nodes
var alice = new Person
{
    FirstName = "Alice",
    LastName = "Smith",
    Age = 30,
    HomeAddress = new Address
    {
        Street = "123 Main St",
        City = "Portland",
        Country = "USA"
    }
};

await graph.CreateNodeAsync(alice);

// Create relationships
var bob = new Person { FirstName = "Bob", LastName = "Jones", Age = 25 };
await graph.CreateNodeAsync(bob);

var friendship = new Knows(alice, bob)
{
    Since = DateTime.UtcNow.AddYears(-2)
};
await graph.CreateRelationshipAsync(friendship);

// Query with LINQ
var youngPeople = await graph.Nodes<Person>()
    .Where(p => p.Age < 30)
    .Where(p => p.HomeAddress != null && p.HomeAddress.City == "Portland")
    .OrderBy(p => p.FirstName)
    .ToListAsync();

// Graph traversal
var alicesFriends = await graph.Nodes<Person>()
    .Where(p => p.FirstName == "Alice")
    .Traverse<Person, Knows, Person>()
    .WithDepth(1, 2)
    .Where(friend => friend.Age > 20)
    .ToListAsync();

5. Transaction Management

await using var transaction = await graph.GetTransactionAsync();
try
{
    await graph.CreateNodeAsync(person, transaction: transaction);
    await graph.CreateRelationshipAsync(relationship, transaction: transaction);
    await transaction.Commit();
}
catch
{
    await transaction.Rollback();
    throw;
}

πŸ“š Documentation

πŸ’‘ Examples

Explore comprehensive examples in the examples/ directory:

πŸ—οΈ Building & Testing

Build Configurations

GraphModel supports multiple build configurations for different scenarios:

# Development (fastest, project references)
dotnet build --configuration Debug

# Local package testing (test package references before publishing)
dotnet build --configuration LocalFeed

# Production builds (package references, requires VERSION file)
dotnet build --configuration Release

For testing package references locally before publishing to NuGet:

# Method 1: Direct LocalFeed build
dotnet build --configuration LocalFeed
dotnet build --configuration Release

# Method 2: Using helper script
./scripts/setup-local-feed-msbuild.sh
dotnet build --configuration Release

# Cleanup when done
dotnet msbuild -target:CleanLocalFeed

See Build System Documentation for complete details.

πŸ—οΈ Architecture

GraphModel follows a clean, layered architecture:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚          Your Application       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        Graph.Model (Core)       β”‚  ← Abstractions & LINQ
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     Graph.Model.Neo4j           β”‚  ← Provider Implementation
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚         Neo4j Database          β”‚  ← Storage Layer
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Components:

  • IGraph - Main entry point for all graph operations
  • INode / IRelationship - Type-safe entity contracts
  • IGraphQueryable - LINQ provider with graph-specific extensions
  • IGraphTransaction - ACID transaction management
  • Attributes - Declarative configuration (Node, Relationship, Property)

πŸ”§ Requirements

  • .NET 9.0 or .NET 10.0 or later
  • Neo4j 4.0+ (5.x recommended for Neo4j provider)
  • C# 12 language features

πŸ“– Related Resources

🀝 Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License

Licensed under the Apache License, Version 2.0. See LICENSE for details.

πŸ™ Acknowledgments

Special thanks to the Neo4j team for creating an excellent graph database and driver ecosystem that makes this library possible.


Built with ❀️ by Savas Parastatidis

About

An abstraction for a Graph that supports LINQ expressions.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •