---
title: AutoQuery CRUD Bookings Demo
---
The powerfully productive combination of [AutoQuery](/autoquery/rdbms) and [Locode](/locode/) can be used to give **Authorized Users an Instant UI** to access AutoQuery Services resulting in an immediate fully queryable (inc. export to Excel) & management UI over system tables within minutes. By virtue of being normal ServiceStack Services, AutoQuery APIs also inherit ServiceStack's ecosystem of features like [Add ServiceStack Reference](/add-servicestack-reference) enabling high-performance end-to-end typed API access in all popular Web, Mobile & Desktop platforms.
## Creating a multi-user .NET Core Booking system in minutes!
To see the rapid development of AutoQuery in action we've created a quick demo showing how to create a simple multi-user Booking System from an empty [web](https://github.com/NetCoreTemplates/web) project, [mixed in](/mix-tool) with the preferred RDBMS & Auth layered functionality, before enabling [Validation](/validation), [AutoQuery](/autoquery/rdbms), Admin Users & [CRUD Event Log](/autoquery/audit-log) plugins - to lay the foundational features before building our App by first defining its `Booking` data model & its surrounding **Query**, **Create**, **Update** and **Soft Delete** Typed CRUD APIs with rich validation enforced by declarative Validation attributes and multi-layer authorization rules & access permissions protected using Authorization attributes.
All declarative functionality is accessible in Locode which is used to create new Employee & Manager Users, before signing in with each to hit the ground running and start entering new bookings using Locode's capability-based UI, with each change visible in its **Audit History**.
### Download and Run
The quickest way to run the [Bookings AutoQuery Example](https://github.com/NetCoreApps/BookingsCrud) is to install the [x tool](/dotnet-tool), download & run the repo:
```bash
x download NetCoreApps/BookingsCrud
cd BookingsCrud\Acme
dotnet run
```
### Custom project from Scratch
If you have different App requirements you can instead create a project from scratch that integrates with your existing preferred infrastructure - the [mix tool](/mix-tool) and ServiceStack's layered [Modular Startup](/modular-startup) configurations makes this a cinch, start with an empty `web` project:
:::sh
npx create-net web ProjectName
:::
Then mix in your desired features. E.g. In order for this project to be self-hosting it utilizes the embedded SQLite database, which we can configure along with configuration to enable popular Authentication providers and an RDBMS SQLite Auth Repository with:
:::sh
npx add-in auth auth-db sqlite
:::
But if you also wanted to enable the new [Sign in with Apple](/auth/signin-with-apple) and use SQL Server you'll instead run:
:::sh
npx add-in auth-ext auth-db sqlserver
:::
You can view all DB and Auth options available by searching for available layered gist configurations by tag:
```bash
npx add-in [db]
npx add-in [auth]
```
Typically the only configuration that needs updating is your DB connection string in [Configure.Db.cs](https://github.com/NetCoreApps/BookingsCrud/blob/main/Acme/Configure.Db.cs), in this case it's changed to use a persistent SQLite DB:
```csharp
services.AddSingleton(new OrmLiteConnectionFactory(
Configuration.GetConnectionString("DefaultConnection")
?? "bookings.sqlite",
SqliteDialect.Provider));
```
You'll also want to create RDBMS tables for any that doesn't exist:
```csharp
using var db = appHost.Resolve().Open();
db.CreateTableIfNotExists();
```
### Create Booking CRUD Services
The beauty of AutoQuery is that we only need to focus on the definition of our C# POCO Data Models which OrmLite uses to create the RDBMS tables and AutoQuery reuses to generates the Typed API implementations enabling us to build full functional high-performance systems with rich querying capabilities that we can further enhance with declarative validation & authorization permissions and rich integrations with the most popular platforms without needing to write any logic.
The `Booking` class defines the Data Model whilst the remaining AutoQuery & CRUD Services define the typed inputs, outputs and behavior of each API available that Queries and Modifies the `Booking` table.
An added utilized feature are the `[AutoApply]` attributes which applies generic behavior to AutoQuery Services.
The `Behavior.Audit*` behaviors below depend on the same property names used in the
[AuditBase.cs](https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Interfaces/AuditBase.cs)
class where:
- `Behavior.AuditQuery` - adds an [Ensure AutoFilter](/autoquery/crud#autofilter) to filter out any deleted records
- `Behavior.AuditCreate` - populates the `Created*` and `Modified*` properties with the Authenticated user info
- `Behavior.AuditModify` - populates the `Modified*` properties with the Authenticated user info
- `Behavior.AuditSoftDelete` - changes the behavior of the default **Real Delete** to a **Soft Delete** by
populating the `Deleted*` properties
```csharp
public class Booking : AuditBase
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public RoomType RoomType { get; set; }
public int RoomNumber { get; set; }
public DateTime BookingStartDate { get; set; }
public DateTime? BookingEndDate { get; set; }
public decimal Cost { get; set; }
public string Notes { get; set; }
public bool? Cancelled { get; set; }
}
public enum RoomType
{
Single,
Double,
Queen,
Twin,
Suite,
}
[AutoApply(Behavior.AuditQuery)]
public class QueryBookings : QueryDb
{
public int[] Ids { get; set; }
}
[ValidateHasRole("Employee")]
[AutoApply(Behavior.AuditCreate)]
public class CreateBooking
: ICreateDb, IReturn
{
public string Name { get; set; }
[ApiAllowableValues(typeof(RoomType))]
public RoomType RoomType { get; set; }
[ValidateGreaterThan(0)]
public int RoomNumber { get; set; }
public DateTime BookingStartDate { get; set; }
public DateTime? BookingEndDate { get; set; }
[ValidateGreaterThan(0)]
public decimal Cost { get; set; }
public string Notes { get; set; }
}
[ValidateHasRole("Employee")]
[AutoApply(Behavior.AuditModify)]
public class UpdateBooking
: IPatchDb, IReturn
{
public int Id { get; set; }
public string Name { get; set; }
[ApiAllowableValues(typeof(RoomType))]
public RoomType? RoomType { get; set; }
[ValidateGreaterThan(0)]
public int? RoomNumber { get; set; }
public DateTime? BookingStartDate { get; set; }
public DateTime? BookingEndDate { get; set; }
[ValidateGreaterThan(0)]
public decimal? Cost { get; set; }
public bool? Cancelled { get; set; }
public string Notes { get; set; }
}
[ValidateHasRole("Manager")]
[AutoApply(Behavior.AuditSoftDelete)]
public class DeleteBooking : IDeleteDb, IReturnVoid
{
public int Id { get; set; }
}
```
### Single Patch Partial Update API
Previously the Edit UI required the full update `IUpdateDb` API, but now supports falling back to using a partial `IPatchDb` API (if exists) where it will instead **only update the modified fields** that have changed.
Ultimately this means for most cases you'll only need to provide a single `IPatchDb` API to update your data model as it allows for the most flexible functionality of only updating any **non-null** values provided. This does mean that every property other than the primary key should either be a **nullable reference or Value Type** (i.e. using `Nullable`).
Using `IPatchDb` Partial Updates are also beneficial in [crud audit logs](/autoquery/audit-log) as they only capture the fields that have changed instead of full record `IUpdateDb` updates.
`IPatchDb` APIs can also be used to reset fields to `null` by specifying them in a `Reset` DTO string collection Property or **Request Param**, e.g. `?reset=Field1,Field2`.
## Manage in Locode
After defining your AutoQuery APIs, start your App then you can use the built-in [Locode UI](/locode/) to manage Bookings at:
https://example.org/locode/
[](/locode/)