Dgraph4Net.Tools 2023.4.296.14

dotnet tool install --global Dgraph4Net.Tools --version 2023.4.296.14
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest # if you are setting up this repo
dotnet tool install --local Dgraph4Net.Tools --version 2023.4.296.14
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Dgraph4Net.Tools&version=2023.4.296.14
nuke :add-package Dgraph4Net.Tools --version 2023.4.296.14

Dgraph4Net

This client are based on Dgraph Go client.
This README is based on Dgraph.net README.

Before using this client, we highly recommend that you go through docs.dgraph.io, and understand how to run and work with Dgraph.

Table of contents

Packages

  • Dgraph4Net.Newtonsoft.Json: NuGet
  • Dgraph4Net: NuGet
  • Dgraph4Net.Core: NuGet

Tools

  • Dgraph4Net.Tools: NuGet
    • For migrations and schema management

Package Publisher

Install

Install using nuget:

dotnet add package Dgraph4Net.Newtonsoft.Json
dotnet add package Dgraph4Net
dotnet add package Dgraph4Net.Core
dotnet tool install Dgraph4Net.Tools

The json packages already references Dgraph4Net.
The package Dgraph4Net already references Dgraph4Net.Core.
The package tool Dgraph4Net.Tools references Dgraph4Net for code generation.

Supported Versions

Dgraph version Dgraph4Net version dotnet Version
1.1.Y 0.3.Y Standard 2.1
20.03.Y 1.X.Y .NET5
21.2.Y 2022.X.Y .NET6
22.0.Y 2023.2.<145X.Z .NET7
23.0.Y 2023.2.>145X.Z .NET7

Using a Client

Creating a Client

Make a new client by passing in one or more GRPC channels pointing to alphas.

var channel = new Channel("localhost:9080", ChannelCredentials.Insecure);
var client = new Dgraph4NetClient(channel);
Using DI

You can use DI to create a client, as seen below:

Add the following line to your appsettings.json file:

{
  "ConnectionStrings": {
    "DgraphConnection": "server=<host_port:9080>;[user id=<username>];[password=<password>];[use tls=<false to insecure is default, no SSL validation>];[api-key=<cloud bearer api key>]"
  }
}

Add the following line to your Startup.cs file:

services.AddDgraph(); // for DefaultConnection string
// or
services.AddDgraph("DgraphConnection"); // for named connection string
// or
services.AddDgraph(sp => "_inline_cs"); // for inline connection string

Mapping Classes

Mapping classes can perform a schema migration and marshaling.

services.AddDgraph(); // already call mapping
// or, for manual mapping
ClassMapping.Map(); // to map all assemblies with classes that implements IEntity
// or
ClassMapping.Map(assemlies); // to map specifics assemblies

**NOTE: your classes need to implement Dgraph4Net.IEntity interface.

Creating mappings

Follow the example below to create a mapping:

// poco types
public class Person : IEntity
{
    public Uid Uid { get; set; } = Uid.NewUid(); // you must initialize Uid
    public string[] DgraphType { get; set; } = Array.Empty<string>();
    public string Name { get; set; }
    public List<Person> BossOf { get; set; } = new List<Person>();
    public Company WorksFor { get; set; }
    public Person? MyBoss { get; set; }
}

public class Company : IEntity
{
    public Uid Uid { get; set; } = Uid.NewUid(); // you must initialize Uid
    public string[] DgraphType { get; set; } = Array.Empty<string>();
    public string Name { get; set; }
    public CompanyIndustry Industry { get; set; }
    public ICollection<Person> WorksHere { get; set; } = new List<Person>();
}

public enum CompanyIndustry
{
    IT,
    Finance,
    Health,
    Food,
    Other
}

// mappings
internal sealed class PersonMapping : ClassMap<Person>
{
    protected override void Map()
    {
        SetType("Person"); // to set the type name
        String(x => x.Name, "name"); // to map a property to name predicate
        HasOne(x => x.WorksFor, "works_for", true, true); // to map a property to an uid predicate
        HasOne(x => x.MyBoss, "my_boss", true, true); // to map a property to an uid predicate
        HasMany(x => x.BossOf, "my_boss", x => x.MyBoss); // to map a property to reversed my_boss
    }
}

internal sealed class CompanyMapping : ClassMap<Company>
{
    protected override void Map()
    {
        SetType("Company"); // to set the type name
        String(x => x.Name, "name"); // to map a property to name predicate
        String<CompanyIndustry>(x => x.Industry, "industry"); // to map a property to string predicate that transforms enum to string
        HasMany(x => x.WorksHere, "works_for", x => x.WorksFor); // to map a property to reversed works_for
    }
}

Creating a Transaction

To create a transaction, call Dgraph4NetClient.NewTransaction method, which returns a new Transaction object. This operation incurs no network overhead.

It is good practice to call to wrap the Transaction in a using block, so that the Transaction.Dispose function is called after running the transaction. Or you can use it on IDisposable services injected as Transient on your application.

await using var txn = client.NewTransaction();
...

You can also create Read-Only transactions. Read-Only transactions only allow querying, and can be created using DgraphClient.NewReadOnlyTransaction.

Running a Mutation

Transaction.Mutate(RequestBuilder) runs a mutation. It takes in a json mutation string.

We define a person object to represent a person and serialize it to a json mutation string. In this example, we are using the JSON.NET library, but you can use any JSON serialization library you prefer.

await using var txn = client.NewTransaction();
var alice = new Person{ Name = "Alice" };
var json = JsonSerializer.Serialize(alice);
var mutation = new Mutation
{
    CommitNow = true,
    DeleteJson = ByteString.CopyFromUtf8(json)
};
    
var response = await txn.Mutate(mutation);

You can also set mutations using RDF format, if you so prefer, as seen below:

var rdf = "_:alice <name> \"Alice\"";
var mutation = new Mutation
{
    CommitNow = true,
    SetNquads = rdf
};
var response = await txn.Mutate(mutation);

Check out the tests as example in tests/DGraph4Net.Tests.

Running a Query

You can run a query by calling Transaction.Query(string). You will need to pass in a GraphQL+- query string. If you want to pass an additional map of any variables that you might want to set in the query, call Transaction.QueryWithVars(string, Dictionary<string,string>) with the variables dictionary as the second argument.

The response would contain the response string.

Let’s run the following query with a variable $a:

query all($a: string) {
  all(func: eq(name, $a))
  {
    name
  }
}

Run the query, deserialize the result from Uint8Array (or base64) encoded JSON and print it out:

// Run query.
var query = @"query all($a: string) {
  all(func: eq(name, $a))
  {
    name
  }
}";

var vars = new Dictionary<string,string> { { $a: "Alice" } };
var res = await client.NewTransaction(true, true).QueryWithVars(query, vars);

// Print results.
Console.Write(res.Json);

You can also create queries with helpers, as seen below:

var vars = new VarTriples();
vars.Add(new("id1", "Alice"));

var query = @$"query Me({vars.ToQueryString()}){{
    me(func: eq({DType<Person>.Predicate(p => p.Name)}, $id1), first: 1) {{
        {DType<Person>.Predicate(p => p.Name)}
        {DType<Person>.Predicate(p => p.Dob)}
        {DType<Person>.Predicate(p => p.Age)}
        {DType<Person>.Predicate(p => p.Married)}
        {DType<Person>.Predicate(p => p.Raw)}
        {DType<Person>.Predicate(p => p.Friends)} @filter(eq({DType<Person>.Predicate(p => p.Name)}, ""Bob"")){{
            {DType<Person>.Predicate(p => p.Name)}
            {DType<Person>.Predicate(p => p.Age)}
            dgraph.type
        }}
        loc
        {DType<Person>.Predicate(p => p.Schools)} {{
            {DType<School>.Predicate(p => p.Name)}
            dgraph.type
        }}
        dgraph.type
    }}
}}";

var res = await client.NewTransaction(true, true).QueryWithVars(query, vars.ToDictionary());

// Print results.
Console.Write(res.Json);

It is useful to prevent predicate and types typos, and also to help with refactoring.

Running an Upsert: Query + Mutation

The Transaction.Mutate function allows you to run upserts consisting of one query and one mutation.

To know more about upsert, we highly recommend going through the docs at https://docs.dgraph.io/mutations/#upsert-block.

var q = $@"
    query Q($email: string) {{
        u as var(func: eq(email, $email))
    }}";

var request = new Request{ Query = query, CommitNow = true };

request.Vars.Add("$userName", "email@dgraph.io");

var mutation = new Mutation{
  SetNquads = @"`uid(user) <email> ""email@dgraph.io"" .",
  Cond = "@if(eq(len(u), 0))",
  CommitNow = true,
};

request.Mutations.Add(mutation);

// Upsert: If email not found, perform a new mutation, or else do nothing.
await txn.Do(request);

Committing a Transaction

A transaction can be committed using the Transaction.Commit method. If your transaction consisted solely of calls to Transaction.Query or Transaction.QueryWithVars, and no calls to Transaction.Mutate, then calling Transaction.Commit is not necessary.

An error will be returned if other transactions running concurrently modify the same data that was modified in this transaction. It is up to the user to retry transactions when they fail.

await using var txn = client.NewTransaction();
try
{
  var rdf = "_:alice <name> \"Alice\"";
  var mutation = new Mutation { SetNquads = rdf };
  var response = await txn.Mutate(mutation);
  txn.Commit();
}
catch
{
  txn.Abort(); // for SQL users - this is like a ROLLBACK TRANSACTION
  throw;
}

Uid propagation after Mutation

DGraph4Net propagates for all instances of Uid struct when a Mutation are performed. To ensure this functionality make sure you are initializing Uid instance.

class MyClass {
  Uid Id { get; set; } = Uid.NewUid(); // is important to every set Id to Uid.NewUid() on construct a type
}

....
await client.Mutate(mutation);

When mutation occurs, all instances of Uid returned by dgraph mutation are updated with the real Uid, it is useful for deep id propagation when you send many objects to dgraph and reduces the async calling to check an object propagation to database or making new queries to retieve the last inserted data or navigating to Uids property returned from mutation.

Migrations

Dgraph4Net has a migration system that allows you to create and update your database schema.

You need to install the package tool Dgraph4Net.Tools to use the migration system.

Creating a Migration

To create a migration, you need to create a class that inherits from Migration and implement the Up and Down method.

dotnet tool install --global Dgraph4Net.Tools

To immediately run database update you can user the -u or --update option.

dgn migration add MyMigrationName -o Migrations --server server:port --project MyProject.csproj [--uid <user_id>] [--pwd <password>] [-u]

The command above will create a migration (.cs) and schema (.cs.schema) files in the Migrations folder of your project.

The schema file will store the current expected schema for your migration and the others created before.

Applying a Migration

To apply a migration, you need to run the command below.

dgn migration up --server server:port --project MyProject.csproj [--uid <user_id>] [--pwd <password>]

Removing a Migration

To remove a migration, you need to run the command below.

dgn migration remove MyMigrationName -o Migrations --server server:port --project MyProject.csproj [--uid <user_id>] [--pwd <password>]

The remove will update the database schema to the previous migration and remove the migration and schema files.

In Development

  • .NET 8
    • Comming in Dec 2023
Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Additional computed target framework(s)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last updated
2023.4.296.14 464 10/23/2023
2023.4.285.18 265 10/12/2023
2023.4.276.11 244 10/3/2023
2023.4.257.18 205 9/14/2023
2023.4.257.15 222 9/14/2023
2023.4.257.4 229 9/14/2023
2023.4.257.3 244 9/14/2023
2023.4.257.2 241 9/14/2023
2023.4.256.22 253 9/13/2023
2023.4.256.20 271 9/13/2023
2023.4.256.12 214 9/13/2023
2023.4.244.22 259 9/1/2023
2023.4.244.19 200 9/1/2023
2023.3.235.7 297 8/23/2023
2023.3.229.14 282 8/17/2023
2023.3.200.11 171 7/19/2023
2023.3.193.8 156 7/12/2023
2023.3.192.17 205 7/11/2023
2023.3.186.15 193 7/5/2023
2023.3.186.14 184 7/5/2023
2023.3.171.15 215 6/20/2023
2023.3.170.17 179 6/19/2023
2023.3.170.16 198 6/19/2023
2023.3.157.23 219 6/6/2023
2023.3.152.21 212 6/1/2023
2023.2.150.23 217 5/30/2023
2023.2.150.22 207 5/30/2023
2023.2.150.21 174 5/30/2023

Update references