N299 EF (Northwind)
Denne opgave er en introduktion til Entity Framework Core (EF Core). Du skal bruge EF Core til at skabe en konsol app, der kan hente og opdatere data fra en SQLite database.
Det er den gode gamle Northwind eksempel database, som du måske kender fra tidligere MS teknologier.
Om Northwind-databasen
Northwind-databasen er en kendt eksempeldatabase fra Microsoft, som oprindeligt fulgte med Microsoft Access som en del af Microsoft Office 2000. Den er designet til at demonstrere forskellige databaseteknologier, herunder relationelle databasefunktioner og SQL-sprog. Northwind repræsenterer data for en fiktiv virksomhed ved navn “Northwind Traders”, der handler med specialfødevarer.
Historie Northwind blev introduceret for at hjælpe udviklere og studerende med at lære at arbejde med databaser ved hjælp af realistiske data. Selvom den ikke længere er inkluderet i de nyeste versioner af Microsoft Access, forbliver Northwind en populær ressource til læring af SQL og databasekoncepter. Den er stadig bredt anvendt som en tutorialdatabase for at lære SQL, på grund af dens enkle struktur og velkendte domæne.
Tabeller og Data Northwind-databasen indeholder tabeller for produkter, medarbejdere, kunder, ordrer, og andre typiske elementer, der findes i en handelsorganisation. Disse tabeller demonstrerer mange almindelige relationelle databasemønstre, herunder et-til-mange og mange-til-mange relationer. For eksempel, Products
-tabellen indeholder oplysninger om de varer, Northwind Traders sælger, mens Orders
-tabellen registrerer kundeordrer.
Relationer Northwind-databasen er et fremragende eksempel på, hvordan relationelle databaser kan modellere komplekse relationer mellem data. Databasen bruger fremmednøgler til at oprette relationer mellem tabeller, hvilket tillader forespørgsler, der krydser flere tabeller, for at hente detaljerede rapporter om virksomhedens drift. For eksempel, en forespørgsel kan hente alle produkter i en bestemt kategori, eller finde alle ordrer placeret af en specifik kunde.
Setup
- Start med at hente Northwind databasen fra linket ovenfor. Gem den i en mappe på din computer - eksempelvis i
c:\temp
.- Hent DB Browser for SQLite fra SQLite.org. Brug dette til at åbne Northwind.db og se indholdet af tabellerne.
- Fra konsollen i eksempelvis
c:\temp
, skab en ny konsol app og tilføj de nødvendige pakker til at kunne arbejde med EF Core og SQLite. - Hent evt SQLite Browser og åbn databasen for at se hvad den består af
dotnet new console -n EFCoreNorthwind
cd EFCoreNorthwind
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package SQLitePCLRaw.bundle_e_sqlite3
- EF fungerer ved at mappe klasser til tabeller i databasen. Start med at skabe en modelklasse for en af tabellerne i Northwind databasen. Du kan vælge at skrive klasserne selv, bruge
Scaffold-DbContext
kommandoen i Package Manager Console i Visual Studio, eller brugedotnet ef dbcontext scaffold
kommandoen i terminalen (sørg for at .NET/VS2022 er helt opdateret):
dotnet new tool-manifest
dotnet tool install dotnet-ef
dotnet ef dbcontext scaffold "Data Source=c:\temp\Northwind.db" Microsoft.EntityFrameworkCore.Sqlite -o Models
-
Dette vil skabe en
Models
mappe med klasser i namespacetEFCoreNorthwind.Models
for alle tabeller i Northwind databasen - herunder enDbContext
klasse, der repræsenterer forbindelsen til databasen. -
Tilføj nu følgende kode til
Program.cs
:
using Microsoft.EntityFrameworkCore;
using EFCoreNorthwind.Models;
SQLitePCL.Batteries.Init();
using var db = new NorthwindContext();
var categories = db.Categories
.Include(c => c.Products)
.ToList();
categories.ForEach(category =>
{
Console.WriteLine($"{category.CategoryName} has {category.Products.Count} products");
category.Products.ToList().ForEach(product =>
{
Console.WriteLine($"\t{product.ProductName}");
});
});
- Det burde give dig en liste over kategorier og produkter i kategorierne. Læg mærke til brugen af Include-metoden, der fortæller EF Core at bruge SQL til at hente produkterne for hver kategori i samme forespørgsel - EF skaber følgende SQL:
SELECT "c"."CategoryID", "c"."CategoryName", "c"."Description", "p"."ProductID", "p"."CategoryID", "p"."Price", "p"."ProductName", "p"."SupplierID", "p"."Unit"
FROM "Categories" AS "c"
LEFT JOIN "Products" AS "p" ON "c"."CategoryID" = "p"."CategoryID"
ORDER BY "c"."CategoryID"
- Hvis du har lyst til at se den SQL, der genereres af EF Core, kan du tilrette OnConfiguring til følgende:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite("Data Source=c:\\temp\\Northwind.db")
.LogTo(Console.WriteLine, new[] { DbLoggerCategory.Database.Command.Name }, LogLevel.Information)
.EnableSensitiveDataLogging();
Opgave
Du skal nu skabe en konsol app, der kan:
- Hente alle of printe alle kunder (
Customers
) i databasen. - Hente og printe alle ordrer for en given kunde (kunde nr. 5 eksempelvis). Du kan evt. bruge
Console.ReadLine()
til at indtasteCustomerId
. Data kan evt komme fraOrder
tabellen. - Hente og vise kunden med flest ordrer. Du kan evt. bruge LINQ til at sortere ordrer for hver kunde og finde den kunde med flest ordrer.
- Hente kunden
Vaffeljernet
og opdatere kundens adresse til “Vaffelvej 1, 1234 Vaffelby”.
Du kan selv finde på flere opgaver, hvis du har lyst.
Klik for at se et forslag til en løsning
using EFCoreNorthwind.Models;
using var context = new NorthwindContext();
var customers = context.Customers.ToList();
foreach (var customer in customers)
Console.WriteLine($"Customer ID: {customer.CustomerId}, Name: {customer.CustomerName}");
Console.Write("Indtast CustomerId: ");
var customerId = Console.ReadLine();
var orders = context.Orders
.Where(o => o.CustomerId == Convert.ToInt32(customerId))
.ToList();
foreach (var order in orders)
Console.WriteLine($"Order ID: {order.OrderId}, Order Date: {order.OrderDate}");
var customerWithMostOrders = context.Customers
.Select(c => new
{
Customer = c,
OrdersCount = c.Orders.Count
})
.OrderByDescending(c => c.OrdersCount)
.First();
Console.WriteLine($"Customer with most orders: {customerWithMostOrders.Customer.CustomerName} - Orders: {customerWithMostOrders.OrdersCount}");
var c = context.Customers
.FirstOrDefault(c => c.CustomerName == "Vaffeljernet");
if (c != null)
{
c.Address = "Vaffelvej 1, 1234 Vaffelby";
context.SaveChanges();
Console.WriteLine("Kundens adresse er opdateret.");
}