Dgraph4Net 2024.4.284.1
dotnet add package Dgraph4Net --version 2024.4.284.1
NuGet\Install-Package Dgraph4Net -Version 2024.4.284.1
<PackageReference Include="Dgraph4Net" Version="2024.4.284.1" />
paket add Dgraph4Net --version 2024.4.284.1
#r "nuget: Dgraph4Net, 2024.4.284.1"
// 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
Tools
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 | Versions 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. |
-
net8.0
- Dgraph4Net.Core (>= 2024.4.284.1)
- Google.Protobuf (>= 3.28.2)
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