Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/mdfrenchman/schematica-dotnet-neo4j

Neo4j.Schema: Tools to manage Neo4j Schema for a Domain Layer in .NET
https://github.com/mdfrenchman/schematica-dotnet-neo4j

csharp neo4j nuget-package schema

Last synced: 19 days ago
JSON representation

Neo4j.Schema: Tools to manage Neo4j Schema for a Domain Layer in .NET

Awesome Lists containing this project

README

        

# SchematicNeo4j
A code-first approach to manage a consistent Neo4j graph schema for a domain layer that is defined in a .NET library.

## For Developers

## New in version 5.0.0
- Relationship Attributes and Relationship Range Index.
- Added default and user specified names for indexes and constraints.
- Added NodeKeyName to the NodeAttribute, allowing for override of the default **nk{firstLabel}**.
- Keeps consistency check by entityName and properties. Covers cases where existing constraints or indexes may already have a generic name from being defined in v3.

#### Upcoming in the next minor release
- Index types other than Range Indexes.
#### Future change
- **potentially breaking change** Changing Extension and CRUD methods to a Fluent pattern to make method discovery and use easier.
- `typeof(Class1).Label()` makes autocomplete method discovery difficult. I'd like to simplify that.
- methods to list schema for export and comparison.

### Using Range Index
Relationship Range Index was added in v5.0.0 and works the same as Indexes on Nodes, except that it ignores the Label and IsAbstract properties.
The `Indexes.Create()` logic uses the class level attribute to differentiate between Relationship | Node.

```csharp
[Relationship]
public class PlaysFor {

[Index()]
[Index(Name="PlaysFor_YearPosition")]
public int Year { get; set; }

[Index(Name="PlaysFor_YearPosition")]
public string Position { get; set; }
}

[Node(Label="Person:Player")]
public class Player : Person {
[Index(Label="Player")]
public string Postion {get; set;}
}
```
Example creates 3 Indexes (all range indexes by default):
1. Relationship Range Index with default name **idx_PlaysFor_Year**
2. Relationship Range Index with name **PlaysFor_YearPosition**
3. Node Range Index with name **idx_Player_Position**

### Defining your domain schema (RELATIONSHIPS)

#### Identifying Relationships
Annotate the class with a RelationshipAttribute (optionally provide a Type, defaults to the class name in proper format).
```csharp
[Relationship]
public class PlaysFor {}

[Relationship(Type="PLAYS_FOR")]
public class Class1 {}
```
Results for both are `()-[:PLAYS_FOR]-()`

### Defining your domain schema (NODES)

#### Identifying Nodes and their Node Key
Annotate the class with a NodeAttribute (or it can also default to the class name)
```csharp
[Node(Label = "Person")]
public class Class1 {}

public class Person {}

[Node]
public class Person {}
```
Annotate the properties that make up the Node Key
```csharp
public class Car {
[NodeKey]
public string Make { get; set; }

[NodeKey]
public string Model { get; set;}
}
```

Name your NodeKey; useful in cases of existing constraints or your project uses a specific naming convention.
The default is nk[firstLabel].
```csharp
[Node(Label="Car:Vehicle", NodeKey="nkCar")]
public class Car {
[NodeKey]
public string Make { get; set; }

[NodeKey]
public string Model { get; set;}
}
```

#### Using Shared (or inherited) Node Keys
If you want to differentiate between 2 subclasses of an object but they are going to share the same node key, defined by the super class.
We can do something like this.
```csharp
public class Person {
[NodeKey]
public string FirstName { get; set; }

[NodeKey]
public string LastName { get; set;}
}

[Node(Label="Person:Coach")]
public class Coach : Person {
public int YearStarted {get; set;}
}

[Node(Label="Person:Player")]
public class Player : Person {
public string Postion {get; set;}
}
```
Both players and coaches have a name; players can be coaches, and vice versa. Either way, this keeps our data clean preventing a person from having 2 records in the system.

## SchematicNeo4j.Extensions
There are a few provided extensions that we can take advantage of when using the CustomAttributes.
Assume the following Vehicle definition:
```csharp
public class Vehicle {
[NodeKey]
public string Make { get; set; }

[NodeKey]
public string Model { get; set;}

[NodeKey]
public string ModelYear { get; set; }

}
```

### We can get the Label by:
```csharp
// for a type
var theLabel = typeof(Vehicle).Label();
```

### We can get the Node Key properties by:
```csharp
// for a type
List vehicleNodeKey = typeof(Vehicle).NodeKey();
```

### We can get the Node Key Name by:
```csharp
// for a type
string vehicleNodeKeyName = typeof(Vehicle).NodeKeyName();
```

## Using SchematicNeo4j.Schema.Initialize
Once we have our domain models identified we can use the `Schema` methods to put it into the graph. You can pass in either an entire assembly, a list, or a single Type.
This will create the indexes for both entity types, node and relationship.
```csharp
// Pass an Assembly and driver
SchematicNeo4j.Schema.Initialize(assembly:Assembly.GetAssembly(typeof(DomainSample.Person)), driver);

// Pass a list of domain types
// Get this assembly
Assembly a = Assembly.GetExecutingAssembly();
// Limit to a specific namespace.
var listOfTypes = a.ExportedTypes.Where(t => t.Namespace == "MyExecutingThing.MyDomain").ToList();
SchematicNeo4j.Schema.Initialize(listOfTypes, driver);

```