Quickstart
Declare a table, insert a row, query it back, update it, and delete it — the full first-use experience from scratch.
Prerequisites
- .NET 10 SDK installed and on your PATH
- A running database instance — PostgreSQL 14+ is currently the only supported engine
Socigy.OpenSource.DBadded to your project — see Installation
1. Declare a table
Annotate a partial class with [Table] and column attributes. The class must be partial so the source generator can augment it with query methods in a companion file.
using Socigy.OpenSource.DB.Core.Attributes;
using Socigy.OpenSource.DB.Core.Values;
[Table("users")]
public partial class User
{
[PrimaryKey, Default(DbDefaults.Guid.Random)]
public Guid Id { get; set; }
public string Username { get; set; } = "anonymous";
public string? Email { get; set; }
[Default(DbDefaults.Time.Now)]
public DateTime CreatedAt { get; set; }
}= "anonymous") is not just a C# default — the source generator reads it and emits DEFAULT 'anonymous' in the DDL for that column. This means the database enforces the same default even for rows inserted outside your application.Build the project once to trigger the source generator:
dotnet buildAfter a successful build, User.Insert(), User.Query(), User.Update(), and User.Delete() are available as if you had written them yourself.
2. Create the table in PostgreSQL
Run this DDL against your database. The CLI tool generates this automatically from your annotated classes — shown here manually for clarity:
CREATE TABLE "users" (
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
"username" TEXT NOT NULL DEFAULT 'anonymous',
"email" TEXT,
"created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY ("id")
);3. Open a connection
using Npgsql;
await using var conn = new NpgsqlConnection(
"Host=localhost;Database=myapp;Username=postgres;Password=secret");
await conn.OpenAsync();Pass this open connection to every command builder with .WithConnection(conn).
4. Insert a row
With ExcludeAutoFields
ExcludeAutoFields() skips all columns that carry a [Default] attribute or a C# initializer. This lets PostgreSQL generate Id and CreatedAt on the server side:
var user = new User { Username = "alice", Email = "[email protected]" };
await user.Insert()
.WithConnection(conn)
.ExcludeAutoFields() // omits Id and CreatedAt — generated by the DB
.ExecuteAsync();With WithValuePropagation
If you want the DB-generated values (Id, CreatedAt) written back into the C# object after the insert, chain WithValuePropagation():
var user = new User { Username = "alice", Email = "[email protected]" };
await user.Insert()
.WithConnection(conn)
.ExcludeAutoFields()
.WithValuePropagation() // populates user.Id and user.CreatedAt from the RETURNING clause
.ExecuteAsync();
Console.WriteLine(user.Id); // now set to the UUID the DB generated
Console.WriteLine(user.CreatedAt); // now set to the server-side NOW()Without ExcludeAutoFields
When you pre-generate the primary key in C#, omit ExcludeAutoFields() to send all columns:
var user = new User
{
Id = Guid.NewGuid(),
Username = "bob",
};
await user.Insert().WithConnection(conn).ExecuteAsync();5. SELECT rows
User.Query() returns an async-enumerable stream. Supply a LINQ expression for the WHERE clause:
await foreach (var u in User.Query(x => x.Username == "alice")
.WithConnection(conn)
.ExecuteAsync())
{
Console.WriteLine($"{u.Id}: {u.Username}");
}Omit the predicate to fetch all rows:
await foreach (var u in User.Query().WithConnection(conn).ExecuteAsync())
{
Console.WriteLine(u.Username);
}6. Update selected fields
Use .WithFields() to restrict the UPDATE to specific columns. The generated UPDATE always uses the primary key in its WHERE clause:
user.Username = "alice-v2";
await user.Update()
.WithConnection(conn)
.WithFields(x => new object[] { x.Username }) // UPDATE only the username column
.ExecuteAsync();To update all non-primary-key columns, omit .WithFields():
await user.Update().WithConnection(conn).ExecuteAsync();7. Delete a row
Delete() uses the primary key column(s) for the WHERE clause automatically:
await user.Delete()
.WithConnection(conn)
.ExecuteAsync();Next steps
- Learn every attribute available for defining models in Tables & classes and Columns & types.
- Explore joins and set operations in Joins and Set operations.
- Set up the migration CLI to generate DDL from your C# classes automatically in CLI tool.
- Configure DI and connection factory generation in Configuration.