Read and write data
Build the endpoints. Insert, query, and stream rows through the typed context sets with predicates instead of SQL.
With the context injected, the endpoints are a few lines each. Every set exposes typed reads and writes that take expression predicates, so the compiler checks your queries.
Create a project
InsertAsync defaults includeAutoFields to false, so the [Default] columns (Id, CreatedAt) are left for the database to fill:
app.MapPost("/projects", (Project project, ISocigyDatabaseFactory<IAppDb> db) =>
db.ExecuteAsync(d => d.Projects.InsertAsync(project)));List a project's tasks
ToListAsync takes an optional predicate and materializes the rows inside the scope:
app.MapGet("/projects/{id:guid}/tasks", (Guid id, ISocigyDatabaseFactory<IAppDb> db) =>
db.ExecuteAsync(d => d.Tasks.ToListAsync(t => t.ProjectId == id)));Add a task
app.MapPost("/projects/{id:guid}/tasks", (Guid id, TaskItem task, ISocigyDatabaseFactory<IAppDb> db) =>
{
task.ProjectId = id;
return db.ExecuteAsync(d => d.Tasks.InsertAsync(task));
});The set API
Each table set (d.Projects, d.Tasks) exposes:
| Method | Returns | Notes |
|---|---|---|
ToListAsync(predicate?) |
Task<List<T>> |
all rows, or those matching the predicate |
FirstOrDefaultAsync(predicate) |
Task<T?> |
first match or null |
ExistsAsync(predicate) |
Task<bool> |
existence check |
CountAsync(predicate?) |
Task<long> |
SELECT COUNT(*) |
InsertAsync(entity, includeAutoFields = false) |
Task<bool> |
one row |
InsertMultipleAsync(entities, ...) |
Task<int> |
batched multi-row insert |
UpdateAsync(entity) |
Task<int> |
update by primary key |
DeleteAsync(predicate) |
Task<int> |
delete matching rows |
ForEachAsync(predicate, onRow) |
Task |
stream rows without buffering |
To process many rows without loading them all into memory, stream with ForEachAsync:
app.MapPost("/projects/{id:guid}/complete-all", (Guid id, ISocigyDatabaseFactory<IAppDb> db) =>
db.ExecuteAsync(d => d.Tasks.ForEachAsync(t => t.ProjectId == id, async task =>
{
task.Done = true;
await d.Tasks.UpdateAsync(task);
})));NOTE
The set methods (
d.Tasks.ToListAsync(...)) are distinct from the static query builder (TaskItem.Query(...)). The builder is for standalone use with your own connection and is covered under Querying; the set methods run inside the context scope.The last endpoint, creating a project and its tasks atomically, needs a transaction. Continue to Transactions and tests.