Dgraph4Net 2024.4.284.1

dotnet add package Dgraph4Net --version 2024.4.284.1                
NuGet\Install-Package Dgraph4Net -Version 2024.4.284.1                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Dgraph4Net" Version="2024.4.284.1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Dgraph4Net --version 2024.4.284.1                
#r "nuget: Dgraph4Net, 2024.4.284.1"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Dgraph4Net as a Cake Addin
#addin nuget:?package=Dgraph4Net&version=2024.4.284.1

// Install Dgraph4Net as a Cake Tool
#tool nuget:?package=Dgraph4Net&version=2024.4.284.1                

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
24.0.Y 2023.2.>145X.Z .NET8

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 AEntity
// or
ClassMapping.Map(assemlies); // to map specifics assemblies

**NOTE: your classes need to implement Dgraph4Net.AEntity<T> abstract class.

Creating mappings

Follow the example below to create a mapping:

// poco types
public class Person : AEntity<Person>
{
    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 : AEntity<Company>
{
    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
    }
}
Using Facets

Facets are a way to store metadata for predicates. They are key-value pairs that can be associated with a predicate. Facets can be used to store information like timestamps, geolocations, and other metadata. Facets are stored as part of the predicate, and are returned with the predicate when queried.

You can use i18n facets too, to store multiple languages in the same predicate.

Pay Attention: You MUST NOT map facets.

With Attribute
class MyClass1 : AEntity<MyClass1> {
    public List<MyClass2> Classes { get; set; }
}

class MyClass2 : AEntity<MyClass2> {
    [Facet<MyClass1>("since", nameof(MyClass1.Classes))]
    public DateTimeOffset Since
    {
        get => GetFacet(DateTimeOffset.MinValue);
        set => SetFacet<DateTimeOffset>(value);
    }
}
With Type

You can use the FacetPredicate<T, TE> on your predicate or create a custom one likes:

class MyCustomFacets(MyClass3 instance, string value = default) : FacetPredicate<MyClass3, string>(instance, property => property.Name, value) {
    public string Origin
    {
        get => GetFacet("origin", "american");
        set => SetFacet("origin", value);
    }
}

class MyClass3 : AEntity<MyClass3> {
    public MyCustomFacets Name { get; set; }
}

Note: Custom facets must have a constructor with two arguments (in order): ClassType for instance and the value of predicate.

With direct access

Use it if you need to gets or sets any facet inside an object.

...
var mc = new MyClass();

// - Getter
mc.GetFacet("property|facet", defaultValue);
mc.GetFacet(m => m.Property, "facet", defaultValue);

// - Setter
mc.SetFacet("property|facet", value);
mc.SetFacet(m => m.Property, "facet", value);

// - i18n, use an 'at' (@) instead of a 'pipe' (|); if using expression selection, put the 'at' at the start of facet name
// - Getter
mc.GetFacet("property@es", defaultValue);
mc.GetFacet(m => m.Property, "@es", defaultValue);

// - Setter
mc.SetFacet("property@es", value);
mc.SetFacet(m => m.Property, "@es", value);
...

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

  • LINQ for dgraph

Notes

Now we will only update the .NET version when it is a LTS version.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Dgraph4Net:

Package Downloads
Dgraph4Net.Identity

Dgraph4Net is based on dgo (https://github.com/Dgraph-io/dgo), a Dgraph client for GoLang.

Dgraph4Net.Newtonsoft.Json

Dgraph4Net is based on dgo (https://github.com/Dgraph-io/dgo), a Dgraph client for GoLang.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2024.4.284.1 128 10/10/2024
2023.4.296.14 638 10/23/2023
2023.4.285.18 449 10/12/2023
2023.4.276.11 439 10/3/2023
2023.4.257.18 514 9/14/2023
2023.4.257.15 471 9/14/2023
2023.4.257.4 474 9/14/2023
2023.4.257.3 487 9/14/2023
2023.4.257.2 439 9/14/2023
2023.4.256.22 452 9/13/2023
2023.4.256.20 487 9/13/2023
2023.4.256.12 487 9/13/2023
2023.4.244.22 531 9/1/2023
2023.4.244.19 520 9/1/2023
2023.3.235.7 477 8/23/2023
2023.3.229.14 490 8/17/2023
2023.3.200.11 590 7/19/2023
2023.3.193.8 595 7/12/2023
2023.3.192.17 571 7/11/2023
2023.3.186.15 612 7/5/2023
2023.3.186.14 601 7/5/2023
2023.3.171.15 659 6/20/2023
2023.3.170.17 586 6/19/2023
2023.3.170.16 607 6/19/2023
2023.3.157.23 648 6/6/2023
2023.3.152.21 601 6/1/2023
2023.2.150.23 605 5/30/2023
2023.2.150.22 572 5/30/2023
2023.2.150.21 594 5/30/2023
2023.2.145.21 805 5/25/2023
2023.2.138.21 768 5/18/2023
2023.2.131.21 724 5/11/2023
2023.2.124.21 776 5/4/2023
2023.2.117.21 845 4/27/2023
2023.2.110.21 802 4/20/2023
2023.2.109.11 845 4/19/2023
2022.2.110.13 1,541 4/20/2022
2022.2.69.16 1,171 3/10/2022
2022.1.53.19 1,212 2/22/2022
2021.12.6 1,291 12/6/2021
2021.11.10 1,057 11/10/2021
1.1.2 1,313 3/10/2021
1.1.1 1,220 2/2/2021
1.1.0 1,190 1/28/2021
1.0.0 1,635 7/14/2020
0.5.0 1,736 6/8/2020
0.4.4 1,699 4/6/2020
0.4.2 2,036 3/19/2020
0.4.0 1,646 3/19/2020
0.3.0 1,649 3/17/2020
0.2.0 1,839 2/29/2020
0.1.0 1,126 2/12/2020

Update references