Övning — Code-First dagbok
En dagboksapp i konsolen: skriv ett inlägg, se dina tidigare inlägg, allt sparat i en riktig databas. Ingen webbserver, inget UI-krångel — bara modellen, kontexten och en meny, vilket gör den perfekt för att öva Code-First-flödet från noll.
Code-First betyder att du skriver C#-klasserna först och låter EF Core generera databasschemat från dem, via migrationer. Motsatsen — Database-first — går åt andra hållet: du har redan en databas och genererar C#-klasserna från den. I den här övningen kör vi Code-First.
Förutsättningar
- .NET SDK installerat
Microsoft.EntityFrameworkCore.SqliteochMicrosoft.EntityFrameworkCore.Design
dotnet new console -n DiaryAppcd DiaryAppdotnet add package Microsoft.EntityFrameworkCore.Sqlitedotnet add package Microsoft.EntityFrameworkCore.DesignSteg 1: Modellen
DiaryEntry.cs:
using System.ComponentModel.DataAnnotations;
public class DiaryEntry{ public int Id { get; set; }
[Required] [MaxLength(100)] public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; } = DateTime.Now;}Steg 2: DbContext
DiaryContext.cs — kontexten tar emot sina options utifrån, den konfigurerar inte sig själv (se Kontext):
using Microsoft.EntityFrameworkCore;
public class DiaryContext : DbContext{ public DiaryContext(DbContextOptions<DiaryContext> options) : base(options) { }
public DbSet<DiaryEntry> DiaryEntries { get; set; }}Steg 3: Skapa migrationen
dotnet ef migrations add InitialCreatedotnet ef database updateSe Migrationer om kommandona känns nya.
Steg 4: Program.cs
Ingen ASP.NET-server behövs för en DI-container — ServiceCollection räcker för en konsolapp:
using Microsoft.EntityFrameworkCore;using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();services.AddDbContext<DiaryContext>(options => options.UseSqlite("Data Source=diary.db"));
using var provider = services.BuildServiceProvider();using var scope = provider.CreateScope();var context = scope.ServiceProvider.GetRequiredService<DiaryContext>();
while (true){ Console.WriteLine(); Console.WriteLine("1. Visa alla inlägg"); Console.WriteLine("2. Skriv ett nytt inlägg"); Console.WriteLine("0. Avsluta");
switch (Console.ReadLine()) { case "1": await ShowAllEntriesAsync(context); break; case "2": await CreateNewEntryAsync(context); break; case "0": return; default: Console.WriteLine("Ogiltigt val."); break; }}
static async Task ShowAllEntriesAsync(DiaryContext context){ var entries = await context.DiaryEntries .OrderByDescending(e => e.CreatedAt) .ToListAsync();
if (entries.Count == 0) { Console.WriteLine("Inga inlägg än."); return; }
foreach (var entry in entries) { Console.WriteLine($"[{entry.CreatedAt:yyyy-MM-dd}] {entry.Title}"); Console.WriteLine(entry.Content); Console.WriteLine(); }}
static async Task CreateNewEntryAsync(DiaryContext context){ Console.WriteLine("Titel:"); var title = Console.ReadLine() ?? string.Empty;
Console.WriteLine("Innehåll:"); var content = Console.ReadLine() ?? string.Empty;
context.DiaryEntries.Add(new DiaryEntry { Title = title, Content = content }); await context.SaveChangesAsync();
Console.WriteLine("Sparat.");}Toppnivå-Main, async/await genomgående och en riktig DI-container istället för new DiaryContext() utspridd i koden — samma mönster du kommer använda i en webbapp, bara utan webbservern runt omkring.
Steg 5: Kör
dotnet runSkriv ett par inlägg, avsluta, kör igen — och se att de fortfarande finns där. Det är hela poängen med att ha en databas istället för en lista i minnet.
Bygg vidare
- Lägg till redigering och radering av inlägg (
context.DiaryEntries.Update(...)/.Remove(...)) - Lägg till en
Mood-property och gruppera inlägg efter humör med LINQ (se LINQ-frågor) - Byt
Console.ReadLine()-menyn mot ett enkelt REST-API ovanpå sammaDiaryContext
Obligatorisk dad-joke
Varför skrev dagboksappen aldrig något dåligt om sig själv?
Den hade redan SaveChanges() inbyggt.