AutoCrud
Sharkable provides automatic CRUD API generation via IAutoCrudEntity<T>. Implement this marker interface on any ISharkEndpoint class, and safe CRUD operations are generated automatically — paginated by default, with zero additional configuration.
Why SqlSugar
Sharkable.AutoCrud is built on SqlSugar — a lightweight, high-performance ORM for .NET:
| License | MIT — no restrictions, commercial-friendly |
| Databases | MySQL, SQL Server, PostgreSQL, SQLite, Oracle, MariaDB, 达梦, 人大金仓, 瀚高, GaussDB, DuckDB, MongoDB, QuestDB, ClickHouse, OceanBase, DB2, HANA, TDSQL, ODBC |
| Performance | Close to raw ADO.NET — faster than EF Core in benchmarks |
| AOT support | StaticConfig.EnableAot = true — compatible with .NET Native AOT |
| No tracking overhead | Queries return plain POCO objects by default, zero change-tracking cost |
| LINQ + Lambda + SQL | Full LINQ support with Where/OrderBy/Select, plus raw SQL when needed |
| Code-first / DB-first | Auto-migrate from entities or reverse-engineer from existing databases |
| Tenant support | Built-in multi-tenant table/DB isolation via SugarTenant |
| Split-table / split-db | Horizontal partitioning and sharding out of the box |
| Seed data | Built-in data seeder for test/demo environments |
All of these work with Sharkable.AutoCrud without extra configuration — the generator maps IAutoCrudEntity<T> directly to SqlSugar's Queryable<T>/Insertable<T>/Updateable<T>/Deleteable<T> APIs.
Quick Start
1. Install Plugin
dotnet add package Sharkable.AutoCrud.SqlSugar
2. Configure Database
builder.Services.AddShark(opt =>
{
opt.ConfigureAutoCrud(s =>
{
s.DbType = DbType.Sqlite;
s.ConnectionString = "DataSource=app.db";
});
});
3. Define Entity + Endpoint
[SugarTable("products")]
public class Product
{
[SugarColumn(IsPrimaryKey = true)]
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
public class ProductEndpoint : ISharkEndpoint, IAutoCrudEntity<Product>
{
// Empty — safe CRUD auto-generated (paginated, no full dump)
}
Generated routes at api/product:
| Method | Route | Operation | Description |
|---|---|---|---|
GET | / | Paginated list | ?page=1&pageSize=20 → {items,total,page,pageSize,totalPages} |
GET | /{id} | Get by PK | Single entity |
POST | / | Create | Request body = entity |
PUT | /{id} | Update | Request body = entity |
DELETE | /{id} | Delete | By PK |
Pagination
List returns paginated results by default. No extra config needed:
GET /api/product?page=1&pageSize=20
{
"items": [{ "id": 1, "name": "Widget", "price": 9.99 }, ...],
"total": 847,
"page": 1,
"pageSize": 20,
"totalPages": 43
}
Default page size is 20; maximum is 100. Both are configurable via SqlSugarOptions:
builder.Services.AddShark(opt =>
{
opt.ConfigureAutoCrud(s =>
{
s.DbType = DbType.Sqlite;
s.ConnectionString = "DataSource=app.db";
s.MaxPageSize = 200;
s.DefaultPageSize = 50;
});
});
Unknown fields in query params are silently ignored.
Suppress Operations
Use AllowedOperations to selectively disable CRUD operations:
public class ReadOnlyEndpoint : ISharkEndpoint, IAutoCrudEntity<Product>
{
CrudOperations IAutoCrudEntity<Product>.AllowedOperations =>
CrudOperations.List | CrudOperations.Get;
// POST, PUT, DELETE suppressed
}
Available flags: None, List, Get, Create, Update, Delete, ListAll, All.
All = List | Get | Create | Update | Delete— does not includeListAll. Full-table dumps must be explicitly opted into for safety.
Enable Full-Table Dump
CrudOperations IAutoCrudEntity<Product>.AllowedOperations =>
CrudOperations.All | CrudOperations.ListAll;
// Now GET /all returns the entire table
ListAll is intentionally excluded from All — full dumps are dangerous on large tables.
Custom Override
Write your own routes in AddRoutes() — they take precedence over auto-generated ones:
public class ProductEndpoint : ISharkEndpoint, IAutoCrudEntity<Product>
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapGet("/", async (ISqlSugarClient db) =>
{
var list = await db.Queryable<Product>()
.Where(p => p.Price > 0)
.OrderBy(p => p.Name)
.ToListAsync();
return Results.Ok(list);
});
}
// Get, Create, Update, Delete still auto-generated
}
Search & Filtering
The List operation supports filtering via filter[field][op]=value query parameters, plus sorting and pagination — all automatically, no code changes needed.
URL Convention
GET /api/product?filter[price][gte]=100&filter[price][lte]=500&filter[name][like]=Widget%&sort=-price&page=1&pageSize=20
Operators
| Key | SQL | Example |
|---|---|---|
| (no op) | = | ?filter[name]=Widget |
eq | = | ?filter[name][eq]=Widget |
ne | <> | ?filter[price][ne]=0 |
gt / gte | > / >= | ?filter[price][gte]=100 |
lt / lte | < / <= | ?filter[price][lte]=500 |
like | LIKE | ?filter[name][like]=Widget% |
in / nin | IN / NOT IN | ?filter[status][in]=active,pending |
null | IS NULL | ?filter[deleted][null]=true |
Sorting
?sort=field (asc), ?sort=-field (desc), ?sort=-price,+name (multi-field).
Safety
Unknown fields are silently ignored. All values are parameterized.
Frontend Example
const params = new URLSearchParams({
'filter[price][gte]': 100,
'filter[name][like]': 'Widget%',
sort: '-price'
});
fetch(`/api/product?${params}`);
Health Check
When EnableHealthChecks = true, SqlSugar connectivity is automatically checked via /healthz:
{
"checks": {
"SqlSugar": {
"status": "healthy",
"description": "SqlSugar connected in 3ms",
"data": { "latencyMs": 3, "dbType": "Sqlite" }
}
}
}
Soft Delete
Mark an entity with ISoftDeletable and AutoCrud handles soft deletion automatically — no code changes needed:
public class Product : ISoftDeletable
{
public int Id { get; set; }
public bool IsDeleted { get; set; } // convention-based detection
}
Behavior:
| Operation | Without ISoftDeletable | With ISoftDeletable |
|---|---|---|
| List / Get / ListAll | All rows | WHERE IsDeleted = 0 only |
| Delete | Hard delete | UPDATE SET IsDeleted = 1 (soft) |
The IsDeleted property is detected by name (case-insensitive). No attributes, no configuration — just add the interface.
The field name is configurable via SqlSugarOptions if your entity uses a different name:
builder.Services.AddShark(opt =>
{
opt.ConfigureAutoCrud(s =>
{
s.SoftDeleteFieldName = "IsRemoved";
});
});
public class Product : ISoftDeletable
{
public int Id { get; set; }
public bool IsRemoved { get; set; } // custom field name
}
AOT Support (Zero rd.xml)
.NET Native AOT publishing requires all types to be known at compile time — the trimmer removes unreferenced types. Normally, SqlSugar entities need manual rd.xml entries to survive trimming.
Sharkable ships a Source Generator that discovers all IAutoCrudEntity<T> implementations and emits typeof(T) references for every entity type — forcing the trimmer to preserve them. No rd.xml needed.
dotnet publish -c Release -r linux-x64 --self-contained
# Entity types are preserved automatically
Works with any Sharkable.AutoCrud.SqlSugar version that depends on Sharkable ≥ 0.4.1.
Architecture
- Sharkable core provides
IAutoCrudEntity<T>+CrudOperations+IAutoCrudGenerator+FilterOperator - Sharkable.AutoCrud.SqlSugar implements
IAutoCrudGeneratorwith SqlSugar ORM - AOT preservation via built-in Source Generator (zero config)
- Future ORM plugins can implement
IAutoCrudGeneratorfor other databases (EF Core, Dapper, etc.)