π Reader: SQL (Jaar 1)
In deze module leer je stap voor stap werken met SQL en databases.
Je leert hoe je data kunt ophalen, filteren, sorteren, combineren en analyseren.
Daarna koppel je de database aan .NET Core en voer je dezelfde queries uit in C# met Entity Framework (ORM).
- Je leert SQL queries schrijven
- Je leert werken met een echte database
- Je leert tabellen en relaties begrijpen
- Je leert data analyseren
- Je leert dezelfde logica toepassen in SQL en in C#
Databases vormen de basis van veel informatiesystemen.
Als je begrijpt hoe data wordt opgeslagen, gekoppeld en opgevraagd, begrijp je ook beter hoe administratiesystemen, webapplicaties en backend software werken.
- Voorbereiding op stages en projecten
- Sterke basis voor backend ontwikkeling
- Inzicht in datamodellen en informatiestromen
- Betere voorbereiding op ORM en API-ontwikkeling
πΉ Week 1 β Intro Database & SELECT
πΉ Week 2 β WHERE & Filtering
πΉ Week 3 β ORDER BY & DISTINCT
πΉ Week 4 β Joins & Relaties
πΉ Week 5 β GROUP BY & Aggregaties
πΉ Week 6 β Database Begrijpen
πΉ Week 7 β EF Core Scaffolding
πΉ Week 8 β SQL vs LINQ & Eindopdracht
πΊ LessonUp
(toevoegen)
π― Focus
- Wat is een database
- Tabellen en kolommen herkennen
selectenfrom- Data ophalen uit één tabel
π§ͺ Praktijk
- Eerste queries uitvoeren in phpMyAdmin
- Resultaten lezen en controleren
- Verschil zien tussen alle kolommen en een selectie van kolommen
π Aanvullende Lesnotities / Opdrachten
Hieronder vind je het uitgebreide weekbestand dat extra uitleg en opdrachten bevat.
In deze week leer je hoe je gegevens uit een tabel ophaalt.
Je gebruikt hiervoor het SQL-commando select.
Met select bepaal je welke kolommen je wilt zien.
Met from geef je aan uit welke tabel de data moet komen.
Een eenvoudige query ziet er zo uit:
select *
from klanten;Met * vraag je alle kolommen op uit de tabel.
Je kunt ook alleen bepaalde kolommen tonen:
select naam, plaats
from klanten;Dan zie je alleen de kolommen naam en plaats.
π’ Beginner
- Toon alle gegevens van alle klanten.
select *
from klanten;- Toon alleen de naam en plaats van alle klanten.
select naam, plaats
from klanten;- Toon alle gegevens van alle producten.
select *
from producten;- Toon de omschrijving en prijs van alle producten.
select omschrijving, prijs
from producten;π‘ Intermediate
- Toon de naam, plaats en het telefoonnummer van alle klanten.
select naam, plaats, telnr
from klanten;- Toon de klantnaam en woonplaats met aliassen.
select naam as klantnaam, plaats as woonplaats
from klanten;- Toon alle producten met een berekende prijs inclusief 21% btw.
select omschrijving, prijs, prijs * 1.21 as prijs_incl_btw
from producten;π Advanced
- Toon een samengestelde weergave van klanten in één kolom.
select concat(naam, ' - ', plaats) as klant_weergave
from klanten;- Geef per klant aan of deze lokaal of extern is op basis van plaats.
select naam,
case
when plaats = 'Haarlem' then 'Lokaal'
else 'Extern'
end as type_klant
from klanten;- Toon unieke combinaties van plaats en postcode.
select distinct plaats, postcode
from klanten;- Controleer altijd eerst uit welke tabel je gegevens wilt halen.
- Begin met
select *als je nog niet precies weet welke kolommen je nodig hebt. - Schrijf kolomnamen nauwkeurig over om fouten te voorkomen.
π Terug naar navigatie
πΊ LessonUp
(toevoegen)
π― Focus
where- Vergelijkingen met
=,>,<,<>,>=,<= likebetween
π§ͺ Praktijk
- Data filteren op basis van voorwaarden
- Resultaten verkleinen zodat alleen relevante data overblijft
- Verschil zien tussen numerieke filters en tekstfilters
π Aanvullende Lesnotities / Opdrachten
Hieronder vind je het uitgebreide weekbestand dat extra uitleg en opdrachten bevat.
In deze week leer je hoe je niet alles toont, maar alleen de rijen die voldoen aan een voorwaarde.
Daarvoor gebruik je where.
Met where kun je bijvoorbeeld klanten uit één plaats tonen of producten boven een bepaalde prijs.
Een filter op tekst ziet er zo uit:
select *
from klanten
where plaats = 'Haarlem';Een filter op een getal ziet er zo uit:
select *
from producten
where prijs > 500;Je kunt ook zoeken op een bereik:
select *
from producten
where prijs between 100 and 500;π’ Beginner
- Toon alle klanten uit Haarlem.
select *
from klanten
where plaats = 'Haarlem';- Toon alle producten met een prijs groter dan 500.
select *
from producten
where prijs > 500;- Toon alle producten met een voorraad kleiner dan 10.
select *
from producten
where voorraad < 10;- Toon alle klanten die niet uit Haarlem komen.
select *
from klanten
where plaats <> 'Haarlem';π‘ Intermediate
- Toon alle producten met een prijs groter dan 100 Γ©n een voorraad groter dan 10.
select *
from producten
where prijs > 100
and voorraad > 10;- Toon alle klanten uit Haarlem of Amsterdam.
select *
from klanten
where plaats = 'Haarlem'
or plaats = 'Amsterdam';- Toon alle klanten waarvan de naam ergens de letter
abevat.
select *
from klanten
where naam like '%a%';π Advanced
- Toon alle producten die duurder zijn dan de gemiddelde prijs van alle producten.
select *
from producten
where prijs > (
select avg(prijs)
from producten
);- Toon alle klanten die minstens één verkooporder hebben geplaatst.
select *
from klanten
where klantnr in (
select klantnr
from verkooporders
);- Toon alle klanten die nog geen verkooporder hebben geplaatst.
select *
from klanten
where not exists (
select 1
from verkooporders v
where v.klantnr = klanten.klantnr
);- Zet tekst altijd tussen enkele quotes.
- Controleer of je filter op een getal of op tekst werkt.
- Lees je query hardop terug: βtoon alle β¦ waar β¦β.
π Terug naar navigatie
πΊ LessonUp
(toevoegen)
π― Focus
- Sorteren met
order by - Oplopend en aflopend sorteren
- Dubbele waarden verwijderen met
distinct
π§ͺ Praktijk
- Resultaten overzichtelijk ordenen
- Unieke waarden herkennen
- Verschil zien tussen volledige lijsten en unieke waarden
π Aanvullende Lesnotities / Opdrachten
Hieronder vind je het uitgebreide weekbestand dat extra uitleg en opdrachten bevat.
In deze week leer je hoe je resultaten sorteert.
Je gebruikt hiervoor order by.
Daarnaast leer je hoe je dubbele waarden uit een resultaat haalt met distinct.
Sorteren op naam:
select *
from klanten
order by naam;Aflopend sorteren op prijs:
select *
from producten
order by prijs desc;Unieke plaatsen tonen:
select distinct plaats
from klanten;π’ Beginner
- Sorteer alle klanten op naam.
select *
from klanten
order by naam;- Sorteer alle producten op prijs van hoog naar laag.
select *
from producten
order by prijs desc;- Toon alle unieke plaatsen van klanten.
select distinct plaats
from klanten;- Sorteer alle producten op voorraad.
select *
from producten
order by voorraad;π‘ Intermediate
- Sorteer klanten eerst op plaats en daarna op naam.
select *
from klanten
order by plaats, naam;- Toon producten met een berekende prijs inclusief btw en sorteer daarop aflopend.
select omschrijving, prijs, prijs * 1.21 as prijs_incl
from producten
order by prijs_incl desc;- Toon unieke plaatsen en sorteer die alfabetisch.
select distinct plaats
from klanten
order by plaats;π Advanced
- Toon de vijf duurste producten.
select *
from producten
order by prijs desc
limit 5;- Sorteer klantnamen op lengte van de naam.
select naam
from klanten
order by length(naam);- Sorteer producten op de waarde
prijs * voorraadvan hoog naar laag.
select *
from producten
order by (prijs * voorraad) desc;- Gebruik
ascals je expliciet oplopend wilt aangeven. - Gebruik
descals je aflopend wilt sorteren. - Vraag jezelf bij
distinctaf: wil ik unieke rijen of unieke waarden in één kolom?
π Terug naar navigatie
πΊ LessonUp
(toevoegen)
π― Focus
- Tabellen koppelen met
join inner joinleft join- Relaties volgen tussen tabellen
π§ͺ Praktijk
- Data uit meerdere tabellen combineren
- Klanten koppelen aan orders
- Orders koppelen aan facturen
- Facturen koppelen aan betalingen
π Aanvullende Lesnotities / Opdrachten
Hieronder vind je het uitgebreide weekbestand dat extra uitleg en opdrachten bevat.
In deze week leer je hoe je gegevens uit meerdere tabellen combineert.
Dat doe je met een join.
Een join gebruikt de relatie tussen tabellen, bijvoorbeeld een klantnummer of ordernummer.
Een inner join tussen klanten en verkooporders:
select k.naam, v.ordernr
from klanten k
join verkooporders v on v.klantnr = k.klantnr;Een left join laat alle rijen van de linkertabel zien, ook als er geen match is in de rechtertabel.
select f.factuurnr, b.bedrag
from facturen f
left join betalingen b on b.factuurnr = f.factuurnr;π’ Beginner
- Toon de klantnaam met het ordernummer van elke verkooporder.
select k.naam, v.ordernr
from klanten k
join verkooporders v on v.klantnr = k.klantnr;- Toon het ordernummer met het factuurnummer van elke factuur.
select v.ordernr, f.factuurnr
from verkooporders v
join facturen f on f.ordernr = v.ordernr;- Toon het factuurnummer met het betaalde bedrag.
select f.factuurnr, b.bedrag
from facturen f
left join betalingen b on b.factuurnr = f.factuurnr;- Toon het ordernummer met de naam van de klant.
select v.ordernr, k.naam
from verkooporders v
join klanten k on k.klantnr = v.klantnr;π‘ Intermediate
- Toon de naam van de klant met het factuurnummer.
select k.naam, f.factuurnr
from klanten k
join verkooporders v on v.klantnr = k.klantnr
join facturen f on f.ordernr = v.ordernr;- Toon per klant het totale factuurbedrag.
select k.naam, sum(f.bedrag) as totaal_factuurbedrag
from klanten k
join verkooporders v on v.klantnr = k.klantnr
join facturen f on f.ordernr = v.ordernr
group by k.naam;- Toon per klant het aantal verkooporders, ook als dat 0 is.
select k.naam, count(v.ordernr) as aantal_orders
from klanten k
left join verkooporders v on v.klantnr = k.klantnr
group by k.naam;π Advanced
- Toon alle klanten die nog geen verkooporder hebben.
select k.naam
from klanten k
left join verkooporders v on v.klantnr = k.klantnr
where v.ordernr is null;- Toon alle facturen waarvoor nog geen betaling bestaat.
select f.factuurnr
from facturen f
left join betalingen b on b.factuurnr = f.factuurnr
where b.betalingnr is null;- Toon alle klanten waarvan het totaal betaalde bedrag groter is dan 1000.
select k.naam, sum(b.bedrag) as totaal_betaald
from klanten k
join betalingen b on b.klantnr = k.klantnr
group by k.naam
having sum(b.bedrag) > 1000;- Kijk altijd eerst welke kolommen de tabellen aan elkaar koppelen.
- Gebruik aliassen zoals
k,v,fenbom je query leesbaar te houden. - Teken desnoods eerst de relatie op papier voordat je een join schrijft.
π Terug naar navigatie
πΊ LessonUp
(toevoegen)
π― Focus
count,sum,avg,maxgroup byhaving
π§ͺ Praktijk
- Samenvattingen maken van data
- Tellingen en totalen berekenen
- Verschil zien tussen
whereenhaving
π Aanvullende Lesnotities / Opdrachten
Hieronder vind je het uitgebreide weekbestand dat extra uitleg en opdrachten bevat.
In deze week leer je hoe je gegevens samenvat.
Je gebruikt functies zoals count en sum.
Met group by groepeer je data.
Met having filter je groepen nadat de samenvatting is gemaakt.
Aantal orders per klant:
select klantnr, count(*) as aantal_orders
from verkooporders
group by klantnr;Totaal orderbedrag per klant:
select klantnr, sum(orderbedrag) as totaal
from verkooporders
group by klantnr;π’ Beginner
- Tel het aantal orders per klant.
select klantnr, count(*) as aantal_orders
from verkooporders
group by klantnr;- Bereken het totale orderbedrag per klant.
select klantnr, sum(orderbedrag) as totaal
from verkooporders
group by klantnr;- Bereken de gemiddelde prijs van alle producten.
select avg(prijs) as gemiddelde_prijs
from producten;- Zoek de hoogste productprijs.
select max(prijs) as hoogste_prijs
from producten;π‘ Intermediate
- Toon alleen klanten met een totaal orderbedrag groter dan 1000.
select klantnr, sum(orderbedrag) as totaal
from verkooporders
group by klantnr
having sum(orderbedrag) > 1000;- Tel hoeveel producten er per productsoort zijn.
select productsoort, count(*) as aantal_producten
from producten
group by productsoort;- Zoek per klant het hoogste orderbedrag.
select klantnr, max(orderbedrag) as hoogste_order
from verkooporders
group by klantnr;π Advanced
- Toon per klantnaam het totale factuurbedrag.
select k.naam, sum(f.bedrag) as totaal_factuurbedrag
from klanten k
join verkooporders v on v.klantnr = k.klantnr
join facturen f on f.ordernr = v.ordernr
group by k.naam;- Toon alleen klanten met meer dan één order en hun totale orderbedrag.
select klantnr, sum(orderbedrag) as totaal
from verkooporders
group by klantnr
having count(*) > 1;- Toon klanten op volgorde van hoogste totale orderbedrag.
select klantnr, sum(orderbedrag) as totaal
from verkooporders
group by klantnr
order by sum(orderbedrag) desc;- Gebruik
wherevoor het filteren van losse rijen. - Gebruik
havingvoor het filteren van gegroepeerde resultaten. - Geef berekende kolommen een alias zoals
totaalofaantal_orders.
π Terug naar navigatie
πΊ LessonUp
(toevoegen)
π― Focus
- Primary keys
- Foreign keys
- Relaties tussen tabellen
- Datamodel begrijpen voordat je code schrijft
π§ͺ Praktijk
- De structuur van de BitByBit database analyseren
- Primary keys en foreign keys herkennen
- Uitleggen hoe informatie door de database loopt
π Aanvullende Lesnotities / Opdrachten
Hieronder vind je het uitgebreide weekbestand dat extra uitleg en opdrachten bevat.
In deze week ga je niet opnieuw een losse mini-database bouwen, maar juist de bestaande database beter begrijpen.
Dat is belangrijk, omdat je in de eerdere weken al hebt gefilterd, gesorteerd en gejoind op tabellen uit de bestaande BitByBit database.
Om goede SQL-queries te kunnen schrijven, moet je niet alleen de syntax kennen, maar ook weten hoe de tabellen inhoudelijk met elkaar verbonden zijn.
Daarom staat deze week in het teken van analyseren, herkennen en uitleggen.
Een database bestaat uit meerdere tabellen. Elke tabel heeft een eigen functie. De tabel klanten bevat bijvoorbeeld gegevens van klanten, terwijl verkooporders de geplaatste orders bevat. De tabel facturen bevat de facturen die bij orders horen en betalingen bevat de geregistreerde betalingen. Deze tabellen staan niet los van elkaar. Ze zijn met elkaar verbonden via sleutels.
De belangrijkste sleutel is de primary key. Een primary key is een kolom die elke rij in een tabel uniek maakt. In de tabel klanten is dat bijvoorbeeld klantnr. In verkooporders is dat ordernr. Door deze unieke sleutels kan de database precies weten welke rij bedoeld wordt. Zonder primary keys zou de database geen betrouwbare manier hebben om records uit elkaar te houden.
Daarnaast zijn er foreign keys. Een foreign key is een kolom die verwijst naar een primary key in een andere tabel. Zo verwijst verkooporders.klantnr naar klanten.klantnr. Dat betekent dat elke order gekoppeld is aan precies één klant. Op dezelfde manier verwijst facturen.ordernr naar verkooporders.ordernr, en verwijst betalingen.factuurnr naar facturen.factuurnr. Hierdoor ontstaat een keten van informatie: van klant naar order, van order naar factuur, en van factuur naar betaling.
Als je deze structuur begrijpt, snap je ook beter waarom joins werken. Een join is namelijk niets anders dan het combineren van tabellen op basis van zoβn relatie. Wanneer je bijvoorbeeld klantnamen met ordernummers combineert, gebruik je de relatie tussen klanten en verkooporders. Wanneer je openstaande bedragen wilt berekenen, moet je begrijpen hoe orders, facturen en betalingen samenhangen. Deze denkwijze is later ook belangrijk bij ORM en Entity Framework, omdat EF Core dezelfde relaties vertaalt naar classes en navigatie-eigenschappen in C#.
π’ Beginner
-
Zoek in de tabel
klantenwelke kolom de primary key is en noteer deze. -
Zoek in de tabel
verkooporderswelke kolom de primary key is en noteer deze. -
Zoek in de tabel
facturenwelke kolom de primary key is en noteer deze. -
Zoek in de tabel
betalingenwelke kolom de primary key is en noteer deze.
π‘ Intermediate
-
Noteer welke kolom in
verkoopordersverwijst naarklanten. -
Noteer welke kolom in
facturenverwijst naarverkooporders. -
Noteer welke kolom in
betalingenverwijst naarfacturen. -
Schrijf in je eigen woorden op wat het verschil is tussen een primary key en een foreign key.
π Advanced
-
Schrijf de volledige relatie-keten van klant naar betaling uit in één zin.
-
Leg uit waarom een join tussen
klantenenfacturenniet direct kan zonder eerst viaverkooporderste gaan. -
Teken op papier of digitaal een eenvoudig schema van de tabellen
klanten,verkooporders,facturenenbetalingen. -
Bekijk onderstaande query en leg uit welke relaties hierin gebruikt worden.
select k.naam, f.factuurnr, b.bedrag
from klanten k
join verkooporders v on v.klantnr = k.klantnr
join facturen f on f.ordernr = v.ordernr
left join betalingen b on b.factuurnr = f.factuurnr;- Kijk goed naar kolommen die op
nreindigen; dat zijn vaak sleutels. - Denk niet alleen in tabellen, maar in relaties tussen tabellen.
- Als je een query lastig vindt, teken dan eerst de route van de data uit.
π Terug naar navigatie
πΊ LessonUp
(toevoegen)
π― Focus
- Database koppelen aan .NET
- Scaffolden van classes
DbContext- Eerste data ophalen in C#
π§ͺ Praktijk
- Database omzetten naar C# classes
- Eerste queries uitvoeren met Entity Framework Core
- Herkennen van tabellen, properties en relaties in code
π Aanvullende Lesnotities / Opdrachten
Hieronder vind je het uitgebreide weekbestand dat extra uitleg en opdrachten bevat.
In deze week ga je de bestaande database koppelen aan een .NET project.
Daarvoor gebruik je Entity Framework Core Database First.
Met scaffolding laat je EF Core classes genereren op basis van de tabellen uit de database.
Met het volgende commando installeer je EntityFramework
dotnet tool install --global dotnet-efMet het volgende commando genereer je een DbContext en de modelclasses:
dotnet ef dbcontext scaffold "Server=localhost;Port=3306;Database=bitbybit;User=root;Password=;" Pomelo.EntityFrameworkCore.MySql --project BitByBit.Data --output-dir Models --context-dir Context --context BitByBitDbContext --data-annotations --no-onconfiguring --no-pluralize --forceNa het scaffolden kun je de data in C# ophalen, bijvoorbeeld:
var klanten = _db.Klanten.ToList();In deze opdracht werken we met een API-controller in ASP.NET Core. Deze controller haalt gegevens op uit de database en stuurt deze terug als JSON.
using BitByBit.Api.Dtos.Klanten;
using BitByBit.Api.Dtos.Orders;
using BitByBit.Data.Context;
using BitByBit.Data.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Globalization;
namespace BitByBit.Api.Controllers
{
[ApiController]
[Route("api/opdrachten")]
public class AssignmentController : Controller
{
private readonly BitByBitDbContext _db;
public AssignmentController(BitByBitDbContext db)
{
_db = db;
}
// GET: api/opdrachten/opdracht1
[HttpGet("opdracht1")]
public async Task<IActionResult> GetOpdracht1()
{
var klanten = await _db.Klanten.ToListAsync();
return Ok(klanten);
}
}
}Bovenaan het bestand staan verschillende using statements.
using BitByBit.Data.Context;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;Met een using geef je aan welke namespaces beschikbaar zijn binnen dit bestand.
Enkele voorbeelden:
BitByBit.Data.Contextbevat de databasecontext.Microsoft.AspNetCore.Mvcbevat onderdelen voor API-controllers.Microsoft.EntityFrameworkCorebevat Entity Framework Core-functionaliteit zoalsToListAsync().
namespace BitByBit.Api.ControllersEen namespace is een logische indeling van code.
Hiermee groepeer je klassen die bij elkaar horen.
In dit geval bevindt de controller zich binnen:
BitByBit.Api.Controllers
public class AssignmentController : ControllerEen controller verwerkt HTTP-verzoeken die binnenkomen vanuit een browser, mobiele app of frontend.
Wanneer een gebruiker een URL bezoekt die bij deze controller hoort, wordt een method uitgevoerd die een antwoord terugstuurt.
[ApiController]Dit attribuut geeft aan dat deze klasse een API-controller is.
ASP.NET Core voegt hierdoor automatisch extra API-functionaliteit toe, zoals:
- JSON-verwerking
- Modelvalidatie
- Foutafhandeling
[Route("api/opdrachten")]Dit bepaalt het basisadres van de controller.
Alle endpoints binnen deze controller beginnen met:
/api/opdrachten
private readonly BitByBitDbContext _db;De BitByBitDbContext vormt de verbinding tussen de applicatie en de database.
Via deze context kun je tabellen benaderen.
Voorbeeld:
_db.KlantenHiermee wordt de tabel of entity Klanten benaderd.
private readonly BitByBitDbContext _db;De variabele kan alleen binnen deze controller gebruikt worden.
De waarde mag slechts één keer worden ingesteld, namelijk in de constructor.
public AssignmentController(BitByBitDbContext db)
{
_db = db;
}De constructor wordt uitgevoerd wanneer ASP.NET Core een nieuwe controller aanmaakt.
De databasecontext wordt automatisch aangeleverd via Dependency Injection.
Vervolgens wordt deze opgeslagen in:
_dbzodat alle methods de database kunnen gebruiken.
[HttpGet("opdracht1")]Dit attribuut koppelt een URL aan een method.
De onderstaande method wordt uitgevoerd wanneer een GET-request binnenkomt op:
/api/opdrachten/opdracht1
public async Task<IActionResult> GetOpdracht1()Het sleutelwoord async geeft aan dat deze method asynchrone code bevat.
Daardoor kan binnen de method het sleutelwoord await worden gebruikt.
Asynchroon werken zorgt ervoor dat de webserver efficiΓ«nter omgaat met wachttijden tijdens databaseverzoeken.
Task<IActionResult>Een Task vertegenwoordigt een taak die nog bezig kan zijn.
In dit geval betekent dit:
Deze method levert uiteindelijk een IActionResult op.
ASP.NET Core wacht automatisch totdat de taak volledig is uitgevoerd.
var klanten = await _db.Klanten.ToListAsync();await wacht totdat de databasequery klaar is.
Zodra de gegevens zijn opgehaald, wordt de uitvoering van de method hervat.
_db.KlantenDit verwijst naar de tabel Klanten in de database.
Entity Framework gebruikt de gekoppelde entity om gegevens uit deze tabel op te halen.
_db.Klanten.ToListAsync();Deze methode voert de query uit en zet het resultaat om naar een lijst van objecten.
Vergelijkbare SQL-query:
SELECT *
FROM klanten;Het resultaat wordt opgeslagen in:
var klantenWanneer een gebruiker de URL opent:
/api/opdrachten/opdracht1
gebeurt het volgende:
ASP.NET Core ontvangt een GET-request.
De route verwijst naar:
GetOpdracht1()Entity Framework maakt een query voor de tabel Klanten.
De query wordt uitgevoerd op de database.
Alle klanten worden opgehaald.
De resultaten worden opgeslagen in:
var klantenDe gegevens worden teruggestuurd naar de gebruiker.
return Ok(klanten);return Ok(klanten);Deze methode retourneert een succesvol HTTP-resultaat.
HTTP-statuscode:
200 OK
De inhoud van klanten wordt automatisch omgezet naar JSON.
Voorbeeld:
[
{
"klantnr": 1,
"naam": "Jansen BV"
},
{
"klantnr": 2,
"naam": "De Vries BV"
}
]Deze endpoint kun je testen via Swagger:
https://localhost:xxxx/swagger/index.html
Of rechtstreeks via de browser:
https://localhost:xxxx/api/opdrachten/opdracht1
Deze controller maakt een API-endpoint waarmee alle klanten uit de database worden opgehaald.
Belangrijke onderdelen:
AssignmentControllerβ verwerkt HTTP-verzoeken.[Route("api/opdrachten")]β basisadres van de controller.[HttpGet("opdracht1")]β endpoint voor een GET-request._dbβ databasecontext._db.Klantenβ tabel Klanten.ToListAsync()β haalt alle klanten op.awaitβ wacht op het resultaat van de databasequery.Ok(klanten)β stuurt de gegevens terug als JSON.
π’ Beginner
-
Maak een nieuw .NET project aan.
-
Installeer de NuGet packages voor EF Core en Pomelo MySQL.
-
Voer het scaffold-commando uit.
-
Open de gegenereerde
DbContexten zoek deDbSet<Klanten>property.
π‘ Intermediate
-
Zoek de gegenereerde class
Klantenen noteer welke properties deze heeft. -
Zoek de gegenereerde class
Verkoopordersen noteer welke properties deze heeft. -
Zoek in de gegenereerde code een navigatieproperty die laat zien dat een klant meerdere verkooporders kan hebben.
-
Schrijf C# code die alle klanten ophaalt.
var klanten = _db.Klanten.ToList();π Advanced
- Schrijf C# code die alleen de naam en plaats van klanten ophaalt.
var klanten = _db.Klanten
.Select(k => new { k.Naam, k.Plaats })
.ToList();- Schrijf C# code die alle producten ophaalt met prijs groter dan 500.
var producten = _db.Producten
.Where(p => p.Prijs > 500)
.ToList();- Schrijf C# code die alle klanten alfabetisch sorteert op naam.
var klanten = _db.Klanten
.OrderBy(k => k.Naam)
.ToList();- Schrijf C# code die alle unieke plaatsen van klanten toont.
var plaatsen = _db.Klanten
.Select(k => k.Plaats)
.Distinct()
.ToList();- Bekijk de gegenereerde code rustig en vergelijk deze met de database-tabellen.
- Let op het verschil tussen gewone properties en navigatieproperties.
- Gebruik LINQ stap voor stap: eerst ophalen, dan filteren, dan sorteren.
π Terug naar navigatie
πΊ LessonUp
(toevoegen)
π― Focus
- SQL vergelijken met LINQ
Select,Where,OrderByGroupBy,SumSelectMany- Denken in tabellen Γ©n in objecten
π§ͺ Praktijk
- Dezelfde informatievraag oplossen in SQL en in C#
- Eenvoudige en meer complexe vergelijkingen maken
- Relaties volgen via navigatie-eigenschappen
π Aanvullende Lesnotities / Opdrachten
Hieronder vind je het uitgebreide weekbestand dat extra uitleg en opdrachten bevat.
In deze week ga je zien dat SQL en LINQ vaak dezelfde logica uitdrukken, maar op een andere manier.
SQL werkt direct op tabellen in de database.
LINQ werkt op objecten en collecties in C#.
Toch stel je in beide gevallen eigenlijk dezelfde vraag aan je data.
Met Select kies je in LINQ welke velden je wilt tonen. Dat lijkt op select in SQL.
Met Where filter je resultaten, net zoals where in SQL.
Met OrderBy sorteer je data, net zoals order by in SQL.
Als je totalen wilt berekenen, gebruik je in SQL vaak sum, en in LINQ gebruik je .Sum(...).
SelectMany is een belangrijk onderdeel wanneer je door meerdere relaties heen wilt lopen. Stel dat een klant meerdere verkooporders heeft, en dat elke verkooporder weer meerdere facturen heeft. Dan krijg je in C# eigenlijk een lijst van klanten, met daarin een lijst van orders, met daarin weer een lijst van facturen. Met SelectMany maak je van zoβn geneste structuur één platte lijst. Daardoor kun je daarna makkelijker rekenen, filteren of projecteren. Zonder SelectMany blijf je werken met een verzameling van verzamelingen, en dat maakt je query lastiger te begrijpen.
SQL
select naam
from klanten;LINQ
var klanten = _db.Klanten
.Select(k => k.Naam)
.ToList();SQL
select *
from klanten
where plaats = 'Haarlem';LINQ
var klanten = _db.Klanten
.Where(k => k.Plaats == "Haarlem")
.ToList();SQL
select *
from klanten
order by naam;LINQ
var klanten = _db.Klanten
.OrderBy(k => k.Naam)
.ToList();SQL
select klantnr, sum(orderbedrag) as totaal
from verkooporders
group by klantnr;LINQ
var totalen = _db.Verkooporders
.GroupBy(v => v.Klantnr)
.Select(g => new
{
Klantnr = g.Key,
Totaal = g.Sum(v => v.Orderbedrag)
})
.ToList();SQL
select
k.klantnr,
k.naam,
sum(f.bedrag - coalesce(b.betaald_bedrag, 0)) as openstaand_bedrag
from klanten k
inner join verkooporders v
on v.klantnr = k.klantnr
inner join facturen f
on f.ordernr = v.ordernr
left join (
select factuurnr, sum(bedrag) as betaald_bedrag
from betalingen
group by factuurnr
) b
on b.factuurnr = f.factuurnr
group by k.klantnr, k.naam
having sum(f.bedrag - coalesce(b.betaald_bedrag, 0)) > 0
order by k.naam;LINQ
var klantenMetOpenstaand = _db.Klanten
.Select(k => new
{
k.Klantnr,
k.Naam,
OpenstaandBedrag = k.Verkooporders
.SelectMany(v => v.Facturen)
.Sum(f => f.Bedrag - (f.Betalingen.Sum(b => (decimal?)b.Bedrag) ?? 0))
})
.Where(k => k.OpenstaandBedrag > 0)
.OrderBy(k => k.Naam)
.ToList();π’ Beginner
- Schrijf de SQL-query om alle klantnamen op te halen.
select naam
from klanten;- Schrijf de LINQ-query die hetzelfde doet.
var klanten = _db.Klanten
.Select(k => k.Naam)
.ToList();- Schrijf de SQL-query om alle klanten uit Haarlem op te halen.
select *
from klanten
where plaats = 'Haarlem';- Schrijf de LINQ-query die hetzelfde doet.
var klanten = _db.Klanten
.Where(k => k.Plaats == "Haarlem")
.ToList();π‘ Intermediate
- Schrijf de SQL-query om alle klanten op naam te sorteren.
select *
from klanten
order by naam;- Schrijf de LINQ-query die hetzelfde doet.
var klanten = _db.Klanten
.OrderBy(k => k.Naam)
.ToList();- Schrijf de SQL-query om het totale orderbedrag per klantnummer te tonen.
select klantnr, sum(orderbedrag) as totaal
from verkooporders
group by klantnr;- Schrijf de LINQ-query die hetzelfde doet.
var totalen = _db.Verkooporders
.GroupBy(v => v.Klantnr)
.Select(g => new
{
Klantnr = g.Key,
Totaal = g.Sum(v => v.Orderbedrag)
})
.ToList();π Advanced
- Bestudeer de LINQ-query met
SelectManyen leg in je eigen woorden uit waaromSelectManynodig is.
var klantenMetOpenstaand = _db.Klanten
.Select(k => new
{
k.Klantnr,
k.Naam,
OpenstaandBedrag = k.Verkooporders
.SelectMany(v => v.Facturen)
.Sum(f => f.Bedrag - (f.Betalingen.Sum(b => (decimal?)b.Bedrag) ?? 0))
})
.ToList();- Schrijf de SQL-query om alleen klanten met een openstaand bedrag groter dan 0 te tonen.
select
k.klantnr,
k.naam,
sum(f.bedrag - coalesce(b.betaald_bedrag, 0)) as openstaand_bedrag
from klanten k
inner join verkooporders v
on v.klantnr = k.klantnr
inner join facturen f
on f.ordernr = v.ordernr
left join (
select factuurnr, sum(bedrag) as betaald_bedrag
from betalingen
group by factuurnr
) b
on b.factuurnr = f.factuurnr
group by k.klantnr, k.naam
having sum(f.bedrag - coalesce(b.betaald_bedrag, 0)) > 0;- Schrijf de LINQ-query die klanten met een openstaand bedrag groter dan 0 toont.
var klantenMetOpenstaand = _db.Klanten
.Select(k => new
{
k.Klantnr,
k.Naam,
OpenstaandBedrag = k.Verkooporders
.SelectMany(v => v.Facturen)
.Sum(f => f.Bedrag - (f.Betalingen.Sum(b => (decimal?)b.Bedrag) ?? 0))
})
.Where(k => k.OpenstaandBedrag > 0)
.ToList();- Maak een eigen vergelijking tussen één SQL-query en één LINQ-query uit deze week en leg uit welke onderdelen bij elkaar horen.
- Denk eerst in SQL: wat wil je precies weten?
- Vertaal daarna stap voor stap naar LINQ.
- Vergelijk niet alleen de syntax, maar vooral de logica van de query.
π Terug naar navigatie
