|
| 1 | +# Copilot Instructions — Time Travelling Data |
| 2 | + |
| 3 | +This is a conference presentation repository for a session on **SQL Server Temporal Tables**. It contains two parallel demo tracks (T-SQL and EF Core), each in two variants (full and "fast" for 2-minute conference delivery). |
| 4 | + |
| 5 | +## Repository Layout |
| 6 | + |
| 7 | +``` |
| 8 | +Demos/ |
| 9 | + SQLDemo/ # Full T-SQL demo — 15 numbered .sql scripts run in SSMS |
| 10 | + SQLDemoFast/ # 2-minute T-SQL demo — 3 scripts (01-Setup, 02-Observe, 03-TimeTravel) |
| 11 | + EFCoreDemo/ # Full EF Core demo — .NET 6 console app, LocalDB |
| 12 | + EFCoreDemoFast/ # 2-minute EF Core demo — .NET 10 console app, Azure SQL |
| 13 | + FastSetup/ # Shared Terraform for provisioning Azure SQL Server + both databases |
| 14 | +Presentations/ # PDF slide decks from past events |
| 15 | +Resources/ # Supporting materials |
| 16 | +``` |
| 17 | + |
| 18 | +## Building and Running |
| 19 | + |
| 20 | +### EFCoreDemoFast (.NET 10 — current "fast" demo) |
| 21 | + |
| 22 | +```bash |
| 23 | +cd Demos/EFCoreDemoFast |
| 24 | +dotnet restore |
| 25 | +dotnet run |
| 26 | +``` |
| 27 | + |
| 28 | +Before running, copy and configure the connection string: |
| 29 | +```bash |
| 30 | +cp appsettings.example.json appsettings.json |
| 31 | +# Edit appsettings.json — set DefaultConnection to your Azure SQL connection string |
| 32 | +``` |
| 33 | + |
| 34 | +The app drops and recreates the `Employees` temporal table on each run — safe to run repeatedly. |
| 35 | + |
| 36 | +### EFCoreDemo (.NET 6 — full demo, LocalDB) |
| 37 | + |
| 38 | +```bash |
| 39 | +cd Demos/EFCoreDemo |
| 40 | +dotnet ef database update # Creates TTD_EFCore database on LocalDB |
| 41 | +dotnet run |
| 42 | +``` |
| 43 | + |
| 44 | +### SQLDemoFast |
| 45 | + |
| 46 | +Run `01-Setup.sql`, `02-Observe.sql`, `03-TimeTravel.sql` in order in SSMS against the `TemporalDemo` database. |
| 47 | + |
| 48 | +### SQLDemo (full) |
| 49 | + |
| 50 | +Run the numbered scripts in order from within SSMS. Scripts are grouped in folders by topic. |
| 51 | + |
| 52 | +### Infrastructure (Azure SQL) |
| 53 | + |
| 54 | +```bash |
| 55 | +cd Demos/FastSetup/terraform |
| 56 | +cp terraform.tfvars.example terraform.tfvars |
| 57 | +# Edit terraform.tfvars — add subscription ID, location, SQL password |
| 58 | +terraform init |
| 59 | +terraform apply |
| 60 | +``` |
| 61 | + |
| 62 | +One `terraform apply` provisions the server and both databases (`TemporalDemo` for SQL demo, `TemporalEFDemo` for EF demo). |
| 63 | + |
| 64 | +## Key Conventions |
| 65 | + |
| 66 | +### Two parallel tracks, same domain |
| 67 | + |
| 68 | +Both the SQL and EF Core demos use an **Employee** domain (name, title, salary, department) on purpose — the narrative maps directly between the T-SQL `FOR SYSTEM_TIME` clauses and EF Core's `TemporalAll()` / `TemporalAsOf()` / `TemporalBetween()` / etc. Keep the domains in sync when updating demos. |
| 69 | + |
| 70 | +### EF Core temporal configuration |
| 71 | + |
| 72 | +Temporal tables are enabled with a single fluent API call — no period columns on the POCO: |
| 73 | + |
| 74 | +```csharp |
| 75 | +entity.ToTable(tb => tb.IsTemporal()); |
| 76 | +``` |
| 77 | + |
| 78 | +EF manages `PeriodStart`/`PeriodEnd` as **shadow properties**. Access them via: |
| 79 | +```csharp |
| 80 | +EF.Property<DateTime>(emp, "PeriodStart") |
| 81 | +``` |
| 82 | + |
| 83 | +### EFCoreDemoFast resets on every run |
| 84 | + |
| 85 | +`Program.cs` drops and recreates the `Employees` table via raw SQL before seeding. This is intentional for reliable demo resets. The `Migrations/` folder is reference material showing what EF generates — it is not used at runtime in the fast demo. |
| 86 | + |
| 87 | +### EFCoreDemo (full) uses EF migrations |
| 88 | + |
| 89 | +The full demo uses `dotnet ef database update` against `(localdb)\MSSQLLocalDB`, database `TTD_EFCore`. The migration is in `Demos/EFCoreDemo/Migrations/`. |
| 90 | + |
| 91 | +### SQL demo uses HIDDEN period columns |
| 92 | + |
| 93 | +In the SQL demo, `ValidFrom`/`ValidTo` are declared `HIDDEN` — they don't appear in `SELECT *`. To see them, name them explicitly: |
| 94 | +```sql |
| 95 | +SELECT EmployeeId, EmployeeName, ValidFrom, ValidTo FROM dbo.Employee; |
| 96 | +``` |
| 97 | + |
| 98 | +### Connection strings are gitignored |
| 99 | + |
| 100 | +`appsettings.json` in `EFCoreDemoFast/` is gitignored. The safe placeholder is `appsettings.example.json`. Never commit real connection strings. |
| 101 | + |
| 102 | +### EF Core temporal query mapping |
| 103 | + |
| 104 | +| EF Core method | T-SQL equivalent | |
| 105 | +|----------------|-----------------| |
| 106 | +| `TemporalAll()` | `FOR SYSTEM_TIME ALL` | |
| 107 | +| `TemporalAsOf(dt)` | `FOR SYSTEM_TIME AS OF` | |
| 108 | +| `TemporalBetween(start, end)` | `FOR SYSTEM_TIME BETWEEN` | |
| 109 | +| `TemporalFromTo(start, end)` | `FOR SYSTEM_TIME FROM ... TO` | |
| 110 | +| `TemporalContainedIn(start, end)` | `FOR SYSTEM_TIME CONTAINED IN` | |
0 commit comments