Skip to content

Commit cc84e87

Browse files
author
RedIsGaming
committed
feat/update: ORM and Covariance/Contravariance explained and Explicit Loading
1 parent 2459be0 commit cc84e87

File tree

5 files changed

+210
-17
lines changed

5 files changed

+210
-17
lines changed

notes_wpfw/.obsidian/workspace.json

+7-6
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"state": {
1414
"type": "markdown",
1515
"state": {
16-
"file": "csharp/wpfw_deel1/week1/csharp.md",
16+
"file": "csharp/wpfw_deel1/week4/orm_en_linq.md",
1717
"mode": "source",
1818
"source": false
1919
}
@@ -85,7 +85,7 @@
8585
"state": {
8686
"type": "backlink",
8787
"state": {
88-
"file": "csharp/wpfw_deel1/week1/csharp.md",
88+
"file": "csharp/wpfw_deel1/week4/orm_en_linq.md",
8989
"collapseAll": false,
9090
"extraContext": false,
9191
"sortOrder": "alphabetical",
@@ -102,7 +102,7 @@
102102
"state": {
103103
"type": "outgoing-link",
104104
"state": {
105-
"file": "csharp/wpfw_deel1/week1/csharp.md",
105+
"file": "csharp/wpfw_deel1/week4/orm_en_linq.md",
106106
"linksCollapsed": false,
107107
"unlinkedCollapsed": true
108108
}
@@ -125,7 +125,7 @@
125125
"state": {
126126
"type": "outline",
127127
"state": {
128-
"file": "csharp/wpfw_deel1/week1/csharp.md"
128+
"file": "csharp/wpfw_deel1/week4/orm_en_linq.md"
129129
}
130130
}
131131
}
@@ -148,13 +148,14 @@
148148
},
149149
"active": "9f997fb097ca76a3",
150150
"lastOpenFiles": [
151+
"csharp/wpfw_deel1/week7/specflow.md",
151152
"csharp/wpfw_deel1/week2/testen_mocks.md",
152153
"csharp/wpfw_deel1/week3/async_(en_functioneel)_programmeren.md",
153154
"csharp/wpfw_deel1/week4/orm_en_linq.md",
154155
"csharp/wpfw_deel1/week1/csharp.md",
155-
"csharp/wpfw_deel1/week7/specflow.md",
156-
"csharp/wpfw_deel1/week6/api.md",
156+
"primaryconstructor_dependency.png",
157157
"csharp/wpfw_deel1/week5/internet.md",
158+
"csharp/wpfw_deel1/week6/api.md",
158159
"Pasted image 20231210153422.png",
159160
"mock_result.png",
160161
"Pasted image 20231209171503.png",

notes_wpfw/csharp/wpfw_deel1/week1/csharp.md

+122-5
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ public class Program
157157
> The current levels have the following difficulties: Easy.
158158
> Just fucking easy!!! and Hard.
159159
160-
## Contra- and Covariance
160+
## #Contravariance and #Covariance
161+
162+
### #Contravariance and #Covariance Example 1
161163

162164
```C#
163165
//namespace ConsoleApp1
@@ -184,14 +186,20 @@ class Consumer<T> : IConsumer<T> //Contravariance, no return, args.
184186
Console.WriteLine($"This contravariance returns: {obj}.\n");
185187
}
186188
}
187-
188-
public class Variance {} //This class won't be used for this part.
189189

190190
//Add this classes/interfaces in a seperate file or place it somewhere you like.
191191
192192
```
193193

194-
Hier komt later wat uitleg.
194+
Hierboven is de layout voor #contravariantie en #covariantie. Schrik niet. Ik zal precies uitleggen wat het nou eigenlijk is. We maken 2 #interface en #class aan. In IProducer passen we #covariantie toe. Dit geven we expliciet met het keyword #out. Je kunt het zien als argument is uit de method en als return type. #T heeft een return type met waarde #T.
195+
196+
Daarna laten we #class Producer inheriten van IProducer. Beide hebben de #generics waarde van #T. Voor #T returnen we #default. Dit zet alle waardes op #null of de absolute 0 waarde wanneer dit van toepassing is. Dan hebben we een #interface IConsumer. Hier passen we #contravariantie toe. Met het keyword #in maak je #T expliciet #contravariant.
197+
198+
Je ziet dat we geen return type hebben. Wel hebben we een obj argument van type #T. #in is als argument in de method. Dit is van laag naar hoog, #contravariantie is van hoog naar laag. Vervolgens hebben we een #class Consumer met type #T als #generics type. Daarna implementeren we de method met argument obj van type #T. We zetten hier onze #code.
199+
200+
> We zetten daar het volgende in: #Console.WriteLine($"This contravariance returns: {obj}.\n");
201+
202+
### #Contravariance and #Covariance Result
195203

196204
```C#
197205
namespace ConsoleApp1;
@@ -214,7 +222,116 @@ public class Program
214222
215223
```
216224

217-
> Het volgende resultaat is: This contravariance returns: h.
225+
We roepen het programma aan met de #interface en maken twee objecten aan. Hierboven zie je #Covariance en #Contravariance in actie. Het is duidelijk wat het resultaat is van deze code.
226+
227+
> Het volgende resultaat is: This #contravariance returns: h.
228+
229+
### #Contravariance and #Covariance Example 2
230+
231+
We maken een super simpel programma. 2 #class met eentje genaamd: Base en de andere genaamd: Derived. Deze inherited van Base. Beide #class hebben hun eigen method, die iets uitprinten in de #Console . In Program hebben we ook 2 methods die we gebruiken voor de #Action. In de uitleg in de #code kun je precies zien hoe dit nou eigenlijk te werk gaat.
232+
233+
```C#
234+
namespace ConsoleApp1;
235+
236+
public class Base
237+
{
238+
public void PrintBase()
239+
{
240+
Console.WriteLine("Base");
241+
}
242+
}
243+
244+
public class Derived : Base
245+
{
246+
public void PrintDerived()
247+
{
248+
Console.WriteLine("Derived");
249+
}
250+
}
251+
252+
public class Program
253+
{
254+
private static void PrintActionBase(Base b)
255+
{
256+
Console.WriteLine("Action Base");
257+
}
258+
259+
private static void PrintActionDerived(Derived d)
260+
{
261+
Console.WriteLine("Action Derive");
262+
}
263+
264+
public static void Main()
265+
{
266+
var base1 = new Base(); //Invariant met implicit typing
267+
Derived derived1 = new(); //Invariant met new() object
268+
269+
object Base base2 = new Derived(); //Covariant, hoog naar laag
270+
Derived derived2 = new Base(); //Contravariant, laag naar hoog
271+
272+
List<Base> base3 = new List<Derived>(); //Covariant, hoog naar laag
273+
List<Derived> derived3 = new List<Base>(); //Contravariant, laag naar hoog
274+
275+
IEnumerable<Base> base4 = new List<Derived>(); //Covariant, werkt met een type dat hoger is. //In dit geval de IEnumerable. Interfaces kunnen alleen voor de eerste komen te staan.
276+
IEnumerable<Derived> derived4 = new List<Base>(); //Contravariant, werkt niet met een type dat lager is, je krijgt //hierop een error. Type 'Base' doesn't match expected type 'Derived'.
277+
278+
Action<Base> base5 = new Action<Derived>(PrintActionDerived); //Covariant, werkt niet met een type dat hoger is. Je krijgt hierop een error.
279+
Action<Derived> derived5 = new Action<Base>(PrintActionBase); //Contravariant, werkt met eem type dat lager is. In dit geval de Action. Interfaces kunnen alleen voor de eerste komen te staan.
280+
}
281+
}
282+
283+
```
284+
285+
> Hierboven staat in het Nederlands uitgelegd, wat #covariantie en #contravariantie nou doen.
286+
287+
### #Contravariance and #Covariance Example 3
288+
289+
Hier zullen we de boven genoemde voorbeelden nog verder verduidelijken. We maken 2 #interface en #class aan en doen daar iets mee. IGalaxy en Planet zijn #covariant. IPlanet en Orbit zijn #contravariant. We zullen met #object en #string werken. Let goed op de keywords: #out en #in. In de #code staat in het Nederlands beschreven hoe dit allemaal te werk gaat.
290+
291+
```C#
292+
namespace ConsoleApp1;
293+
294+
public interface IGalaxy<out T> //Covariance, keyword => out, want type T is uit de argument list.
295+
{
296+
public T? Covariance(); //Return type T
297+
}
298+
299+
public class Planet : IGalaxy<string> //Verander dit van string naar object en het return type ook, wat merk je op?
300+
{
301+
public string Covariance() => "Planet"; //Return type
302+
}
303+
304+
public interface IPlanet<in T> //Contravariance, keyword => in, want type T is in de argument list.
305+
{
306+
public void Contravariance(T obj); //Argument type T
307+
}
308+
309+
public class Orbit : IPlanet<object> //Verander dit van object naar string en het argument type ook, wat merk je op?
310+
{
311+
public void Contravariance(object obj) => Console.WriteLine(obj); //Argument type
312+
}
313+
314+
public class Program
315+
{
316+
public static void Main()
317+
{
318+
//Allemaal high to low, maar:
319+
320+
IGalaxy<object> galaxy = new Planet(); //Het is covariant, kijk naar de type tussen <>. Ik kan object erin stoppen en
321+
//vervangen met string. Dit werkt, want object is een collectie die de string in zich heeft. Dit werkt.
322+
IGalaxy<string> extraGalaxy = new Planet(); //Invariant type werkt ook.
323+
//IGalaxy<string> g = new Planet(); //Contravariant werkt niet hierop. string kan niet naar object. Zie regel 8/10.
324+
325+
IPlanet<string> planet = new Orbit(); //Het is Contravariant, kijk naar de type tussen <>. Ik kan string erin stoppen
326+
//en vervangen met object. Dit werkt, want string behoort tot een collectie die vanuit object komt. Dit werkt.
327+
IPlanet<object> extraplanet = new Orbit(); //Invariant type werkt ook.
328+
//IPlanet<object> p = new Orbit(); //Covariant werkt niet hierop. object kan niet naar string. Zie regel 18/20.
329+
}
330+
}
331+
332+
```
333+
334+
> Hierboven staat in het Nederlands uitgelegd, wat #covariantie en #contravariantie nou doen.
218335
219336
## Generics and Generic Type Constraints
220337

notes_wpfw/csharp/wpfw_deel1/week2/testen_mocks.md

+6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ We maken een #interface ICalculator met een #generics met type #T. Daaraan geven
5050

5151
Nadat we de Mock hebben, maken we een #class / #struct met de daadwerkelijke implementatie. We maken een Calculator en in de #Primary-Constructor geven we de #interface mee met iCalculator argument. Dit is #Dependency-Injection . Je implementeert niet de #interface, maar geeft dit als waarde mee.
5252

53+
> Hier is hoe #Primary-Constructor werkt met #Dependency-Injection :
54+
55+
![[primaryconstructor_dependency.png]]
56+
57+
> url: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/primary-constructors
58+
5359
De MockCalculator die de #interface implementeert is #Dependency-Inversion. Terug naar Calculator. De argument die meegegeven is een #interface-Injection en de #Property een #setter-Injection. Die is #readonly en #private. We willen niet de Mock implementatie aanroepen. Je ziet ook een #generics constraint met where #T : #INumber #T.
5460

5561
Nu is het alleen mogelijk om arithmatic getallen eraan mee te geven. Als laatste hebben we de twee methods die we in de test gaan gebruiken. De implementatie lijkt bijna hetzelfde als de #interface , maar we kunnen de namen van die method voor de => aanpassen. Voor het gemak laten we het zoals het is. #generics types zijn optioneel. Het is geen requirement voor een Mock.

notes_wpfw/csharp/wpfw_deel1/week4/orm_en_linq.md

+75-6
Original file line numberDiff line numberDiff line change
@@ -347,23 +347,88 @@ public class Program
347347

348348
```
349349

350-
## ORM
350+
## #ORM
351351

352-
Dit wordt later beschreven.
352+
#ORM staat voor Object Relational Mapping en zorgt ervoor dat je data kan aansturen van en naar Databases. Het maakt de vertaalslag naar queries, zodat je niet dit zelf hoeft te schrijven. Terwijl je focust op de datastructuren, doet het #ORM de rest voor je. Hieronder staat een goeie uitleg van #ChatGPT die in het Engels is geschreven.
353+
354+
> Het gaat over wat een #ORM precies oplost en tegen welke problemen je kan aanlopen.
355+
356+
**ChatGPT**
357+
**Object-Relational Mapping (ORM)** is a programming technique that allows data to be seamlessly transferred between an object-oriented system and a relational database system. The main problems that #ORM aims to solve are related to the impedance mismatch between the object-oriented programming paradigm and the relational database model.
358+
359+
### Problems #ORM Solves:
360+
361+
1. **Impedance Mismatch:**
362+
363+
- **Problem:** Object-oriented languages (like Java or C#) represent data using objects, while relational databases store data in tables. The differences between these models create an impedance mismatch.
364+
- **Solution:** #ORM provides a way to map objects to database tables and vice versa, helping to bridge the gap between the object-oriented and relational worlds.
365+
2. **Boilerplate Code:**
366+
367+
- **Problem:** Manually writing SQL queries and mapping database results to objects can be tedious and error-prone, leading to a lot of boilerplate code.
368+
- **Solution:** #ORM tools automate the process of #CRUD (Create, Read, Update, Delete) operations, reducing the amount of boilerplate #code and improving developer productivity.
369+
3. **Database Abstraction:**
370+
371+
- **Problem:** Without #ORM, developers need to write code specific to the database they are using. Switching databases can be challenging.
372+
- **Solution:** #ORM abstracts away the underlying database details, making it easier to switch between different database systems without major code changes.
373+
4. **Maintainability:**
374+
375+
- **Problem:** When the data model changes, manual updates to SQL queries and #object mappings are required, making maintenance challenging.
376+
- **Solution:** #ORM tools often provide automated schema generation and migration tools, making it easier to adapt to changes in the data model.
377+
378+
### Problems Encountered with #ORM:
379+
380+
1. **Performance Overhead:**
381+
382+
- **Issue:** #ORM tools may introduce performance overhead compared to hand-tuned SQL queries, especially for complex or performance-critical applications.
383+
- **Mitigation:** #ORM tools often provide ways to optimize queries, and developers can choose to use native SQL queries when necessary.
384+
2. **Learning Curve:**
385+
386+
- **Issue:** There can be a learning curve associated with understanding and effectively using an #ORM, especially for developers new to the tool.
387+
- **Mitigation:** Training, documentation, and experience can help developers become proficient with the #ORM tool.
388+
3. **Customization Limitations:**
389+
390+
- **Issue:** Some #ORMs might limit the flexibility to perform highly customized or optimized database operations.
391+
- **Mitigation:** Some #ORM tools provide ways to write custom queries or use native SQL when needed, but it depends on the specific #ORM.
392+
4. **Mapping Complex Relationships:**
393+
394+
- **Issue:** Mapping complex relationships between objects and database tables can be challenging and may require additional configuration.
395+
- **Mitigation:** #ORMs often provide features and annotations to handle complex relationships, but developers need to be aware of and properly configure these.
396+
397+
While #ORM tools can greatly simplify database interaction in many scenarios, it's important to be aware of their limitations and potential issues. The choice to use an #ORM should be based on the specific requirements and constraints of the project.
353398

354399
## Explicit, Eager and Lazy #Loading
355400

356-
#Loading is een proces dat geldt voor de Entity Framework (EF) en de omliggende data in het ORM. Welke #Loading je moet gebruiken en welke sneller is aan de #usecase en wat je ermee wilt bereiken. Hieronder zullen alle verschillende #Loading worden beschreven. Omdat dit een best uitgebreid stuk kan zijn, zullen we de #code uit de docs gebruiken en niet zelf aanmaken.
401+
#Loading is een proces dat geldt voor de Entity Framework (EF) en de omliggende data in het #ORM. Welke #Loading je moet gebruiken en welke sneller is aan de #usecase en wat je ermee wilt bereiken. Hieronder zullen alle verschillende #Loading worden beschreven. Omdat dit een best uitgebreid stuk kan zijn, zullen we de #code uit de docs gebruiken en niet zelf aanmaken.
357402

358403
> Url behorend tot de #code voorbeelden: https://blog.jetbrains.com/dotnet/2023/09/21/eager-lazy-and-explicit-loading-with-entity-framework-core/ en https://dzone.com/articles/working-with-lazy-loading-and-eager-loading-in-ent
359404
360405
### Explicit #Loading
361406

362-
Explicit #Loading is het proces.
407+
Explicit #Loading is het proces waar de gegevens worden geladen wanneer je dit specifiek doet. De data wordt alleen opgehaald wanneer dit nodig is. Doe je dit niet? Dan krijg je een lege #collection . Het wordt duidelijk waar de #code voor de query wordt aangeroepen, maar je hebt nog steeds het resultaat + 1 probleem. Hieronder is een voorbeeld van Explicit #Loading .
408+
409+
```C#
410+
var invoices = db.Invoices
411+
.ToList();
412+
413+
// All invoices are already loaded...
414+
foreach (var invoice in invoices)
415+
{
416+
// ...but you'll have to explicitly load invoice lines when they are needed
417+
db.Entry(invoice).Collection(p => p.InvoiceLines).Load();
418+
419+
foreach (var invoiceLine in invoice.InvoiceLines)
420+
{
421+
// ...
422+
}
423+
}
424+
425+
```
426+
427+
> Om Explicit #Loading toe te passen, gebruik je het keyword #Load. Zie het voorbeeld hier.
363428
364429
## Eager #Loading
365430

366-
Eager #Loading is het proces waarop je op een query aanroept en daarboven op de gerelateerde gegevens en die ermee laad. Dit kun je doen met de #Include keyword. Eager #Loading is het tegenovergestelde van Lazy #Loading , want je laad meteen alle gegevens in. Dit kan voor een grote overhead zorgen. Hieronder is een voorbeeld hoe je #Loading kunt toepassen.
431+
Eager #Loading is het proces waarop je op een query iets aanroept en daarboven op de gerelateerde gegevens ermee laad. Dit kun je doen met de #Include keyword. Eager #Loading is het niet het tegenovergestelde van Lazy #Loading , je laad wel meteen alle gegevens in. Dit kan voor een overhead zorgen. Hieronder is een voorbeeld hoe je #Loading kunt toepassen.
367432

368433
```C#
369434
var invoices = db.Invoices
@@ -397,7 +462,7 @@ using (var context = new AdventureWorksContext())
397462

398463
## Lazy #Loading
399464

400-
Lazy #Loading is het proces waarbij de query automatisch worden geladen wanneer dit nodig is. Alleen de nodige gegevens die je verwacht worden geladen. In tegenstelling tot Eager #Loading is Lazy #Loading veel sneller. Dit komt, omdat je niet expliciet aangeeft dat je hierop ook een call wilt doen.
465+
Lazy #Loading is het proces waarbij de query automatisch worden geladen wanneer dit nodig is. Alleen de nodige gegevens die je verwacht worden geladen. In tegenstelling tot Eager #Loading is Lazy #Loading niet perse veel sneller. Je krijgt het volledige resultaat + 1. In het meeste gevallen is het niet aan te raden om dit te gebruiken. Kijk naar de benaming: Lazy.
401466

402467
```C#
403468
var invoices = db.Invoices
@@ -438,3 +503,7 @@ public sealed class NorthwindModelOptimized: NorthwindModel
438503
}
439504

440505
```
506+
507+
### Explicit, Eager and Lazy #Loading Video
508+
509+
> Hier een video: https://www.youtube.com/watch?v=T9fTFynqvCw
60.7 KB
Loading

0 commit comments

Comments
 (0)