Entity Framework (EF) Core overview and first examples
Entity Framework (EF) Core is a lightweight, extensible, open source and cross-platform version of the popular Entity Framework data access technology1.
EF Core can serve as an object-relational mapper (O/RM), which:
EF Core supports many database engines, see Database Providers for details.
With EF Core, data access is performed using a model. A model is made up of entity classes and a context object that represents a session with the database. The context object allows querying and saving data. For more information, see Creating a Model.
EF supports the following model development approaches:
A titolo illustrativo si riporta di seguito un esempio di uso del framework EF Core. Alcuni dettagli saranno chiariti in seguito.
1using System.Collections.Generic;
2using Microsoft.EntityFrameworkCore;
3
4namespace Intro;
5//definizione del DbContext
6public class BloggingContext : DbContext
7{
8 public DbSet<Blog> Blogs { get; set; }
9 public DbSet<Post> Posts { get; set; }
10
11 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
12 {
13 optionsBuilder.UseSqlServer(
14 //questa è la stringa di connessione: varia in base al tipo di database utilizzato e alle configurazioni di accesso - maggiori dettagli in seguito...
15 @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
16 }
17}
18//definizione del data model
19public class Blog
20{
21 public int BlogId { get; set; }
22 public string Url { get; set; }
23 public int Rating { get; set; }
24 public List<Post> Posts { get; set; }
25}
26
27public class Post
28{
29 public int PostId { get; set; }
30 public string Title { get; set; }
31 public string Content { get; set; }
32
33 public int BlogId { get; set; }
34 public Blog Blog { get; set; }
35}
Instances of your entity classes are retrieved from the database using Language Integrated Query (LINQ). For more information, see Querying Data.
1using (var db = new BloggingContext())
2{
3 var blogs = db.Blogs
4 .Where(b => b.Rating > 3)
5 .OrderBy(b => b.Url)
6 .ToList();
7}
Data is created, deleted, and modified in the database using instances of your entity classes. See Saving Data to learn more.
1using (var db = new BloggingContext())
2{
3 var blog = new Blog { Url = "http://sample.com" };
4 db.Blogs.Add(blog);
5 db.SaveChanges();
6}
In this tutorial, you create a .NET Core console app that performs data access against a SQLite database using Entity Framework Core2.
Visual Studio Code
per creare un progetto che utilizza EF Core
con SQLite
. Infatti, un progetto .NET può essere sviluppato, ricorrendo alla .NET CLI, ossia ad un insieme di strumenti (tools
) che permettono di sviluppare, compilare, eseguire e pubblicare applicazioni .NET direttamente dalla command-line (in Windows/Linux/Mac). In questo corso di quarta si farà principalmente riferimento alle modalità operative della .NET CLI per la gestione di progetti in .NET, piuttosto che alle funzionalità di Visual Studio e della Windows Powershell.Visual Studio Code con:
C# Dev Kit
1# creiamo una nuova soluzione
2dotnet new sln -o EFGetStarted
3# spostiamoci nella cartella della soluzione
4cd EFGetStarted
5# creiamo un nuovo progetto di tipo console all'interno della soluzione
6dotnet new console -o EFGetStarted
7# aggiungiamo il progetto alla soluzione
8dotnet sln add EFGetStarted\EFGetStarted.csproj
Top-level statements
) e versione 10.0 (Global using directives
, File-scoped namespace declaration
, Global and implicit usings
)To install EF Core, you install the package for the EF Core database provider(s) you want to target. This tutorial uses SQLite because it runs on all platforms that .NET supports. For a list of available providers, see Database Providers.
1dotnet add package Microsoft.EntityFrameworkCore.Sqlite
1# per impostare il proxy a scuola
2$env:http_proxy="proxy.intranet:3128"
3$env:https_proxy="proxy.intranet:3128"
4# per verificare il valore delle variabili
5echo $env:http_proxy
6echo $env:https_proxy
7# le variabili impostate in questo modo sono attive per la sessione corrente
1# per impostare il proxy a scuola
2http_proxy="proxy.intranet:3128"
3https_proxy="proxy.intranet:3128"
4# per verificare il valore delle variabili
5echo $http_proxy
6echo $https_proxy
1:: per impostare il proxy a scuola
2set http_proxy=proxy.intranet:3128
3set https_proxy=proxy.intranet:3128
4:: per verificare il valore delle variabili
5echo %http_proxy%
6echo %https_proxy%
Define a context class and entity classes that make up the model.
1//file: Model.cs
2using Microsoft.EntityFrameworkCore;
3
4namespace EFGetStarted;
5public class BloggingContext : DbContext
6{
7 public DbSet<Blog> Blogs { get; set; } = null!;
8 public DbSet<Post> Posts { get; set; } = null!;
9 public string DbPath { get; }
10 public BloggingContext()
11 {
12 var folder = Environment.SpecialFolder.LocalApplicationData;
13 var path = Environment.GetFolderPath(folder);
14 DbPath = System.IO.Path.Join(path, "blogging.db");
15 }
16 // The following configures EF to create a Sqlite database file in the
17 // special "local" folder for your platform.
18 protected override void OnConfiguring(DbContextOptionsBuilder options)
19 => options.UseSqlite($"Data Source={DbPath}");
20}
21
22public class Blog
23{
24 public int BlogId { get; set; }
25 public string? Url { get; set; }
26 public List<Post> Posts { get; } = new();
27}
28
29public class Post
30{
31 public int PostId { get; set; }
32 public string? Title { get; set; }
33 public string? Content { get; set; }
34
35 public int BlogId { get; set; }
36 public Blog Blog { get; set; } = null!;
37}
EF Core can also reverse engineer a model from an existing database.
Tip: This application intentionally keeps things simple for clarity. Connection strings should not be stored in the code for production applications. You may also want to split each C# class into its own file.
Program.cs
deve esserci la definizione dell’oggetto BloggingContext
, altrimenti la migrazione va in errore, perché il tool che crea la migrazione non trova il DBContext
.1//File: Program.cs
2using EFGetStarted;
3
4using var db = new BloggingContext();
The following steps use migrations to create a database.
Run the following commands in .NET CLI
1# installiamo il pacchetto dotnet-ef a livello globale
2dotnet tool install --global dotnet-ef
3
4# nel caso il pacchetto dotnet-ef fosse già installato e si volesse effettuare un aggiornamento il comando è
5dotnet tool update --global dotnet-ef
6
7# installiamo il pacchetto Design
8dotnet add package Microsoft.EntityFrameworkCore.Design
9
10# effettuiamo la prima migrazione
11dotnet ef migrations add InitialCreate
12
13# creiamo il database a partire dalla migrazione
14dotnet ef database update
This installs dotnet ef and the design package which is required to run the command on a project. The migrations
command scaffolds a migration to create the initial set of tables for the model. The database update
command creates the database and applies the new migration to it.
Model.cs
crea il database nella cartella: C:\Users\%USERNAME%\AppData\Local\
. Assicurarsi che il file blogging.db
non esista già nella posizione specificata, altrimenti la creazione del database (comando Update-Database
) darà errore. Se provando a creare il database si ottiene il messaggio d’errore SQLite Error 1: ’table “Blogs” already exists’ significa che il database esiste già. Se si vuole ricreare il database da capo bisogna cancellare il vecchio file e lanciare nuovamente il comando seguente nella PMC:
Update-Database
Per aprire il file del database di SQLite, si utilizzi il programma DB Browser
, cliccando sul pulsante Open Database
Si selezioni il file del database di SQLite e si osservi le tabelle create:
Cliccando sul pulsante Browse Data si vede che non ci sono ancora dati nel database.
Inserire dati nel database.
Per inserire dati nel database si modifichi il file Program.cs
con il seguente codice:
1//File: Program.cs
2using EFGetStarted;
3
4using var db = new BloggingContext();
5// Note: This sample requires the database to be created before running.
6Console.WriteLine($"Database path: {db.DbPath}.");
7
8// Create
9Console.WriteLine("Inserting a new blog");
10db.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
11db.SaveChanges();
12
13// Read
14Console.WriteLine("Querying for a blog");
15var blog = db.Blogs
16 .OrderBy(b => b.BlogId)
17 .First();
18Console.WriteLine($"blog: {blog.Url}");
Si mandi in esecuzione il progetto (da Visual Studio Code, oppure dalla command line mediante il comando dotnet run
eseguito nella shell posizionata sulla cartella del progetto) e si osservi il contenuto della tabella Blogs dal programma DB Browser for SQLite:
Modificare il contenuto del blog con BlogId=1 e aggiungere un post associato a questo blog.
Per ottenere questo risultato si modifichi il codice del file Program.cs
come segue:
1using EFGetStarted;
2
3using var db = new BloggingContext();
4// Note: This sample requires the database to be created before running.
5Console.WriteLine($"Database path: {db.DbPath}.");
6
7// Create
8//Console.WriteLine("Inserting a new blog");
9//db.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
10//db.SaveChanges();
11
12//// Read
13Console.WriteLine("Querying for a blog");
14var blog = db.Blogs
15 .OrderBy(b => b.BlogId)
16 .First();
17Console.WriteLine($"blog: {blog.Url}");
18
19// Update
20Console.WriteLine("Updating the blog and adding a post");
21blog.Url = "https://devblogs.microsoft.com/dotnet";
22blog.Posts.Add(
23 new Post { Title = "Hello World", Content = "I wrote an app using EF Core!" });
24db.SaveChanges();
Cancellare un blog e tutti i post ad esso associati.
Per ottenere questo risultato si modifichi il codice del file Program.cs
come segue:
1using EFGetStarted;
2
3using var db = new BloggingContext();
4// Note: This sample requires the database to be created before running.
5Console.WriteLine($"Database path: {db.DbPath}.");
6
7// Create
8//Console.WriteLine("Inserting a new blog");
9//db.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
10//db.SaveChanges();
11
12//// Read
13Console.WriteLine("Querying for a blog");
14var blog = db.Blogs
15 .OrderBy(b => b.BlogId)
16 .First();
17Console.WriteLine($"blog: {blog.Url}");
18
19// Update
20//Console.WriteLine("Updating the blog and adding a post");
21//blog.Url = "https://devblogs.microsoft.com/dotnet";
22//blog.Posts.Add(
23// new Post { Title = "Hello World", Content = "I wrote an app using EF Core!" });
24//db.SaveChanges();
25
26// Delete
27Console.WriteLine("Delete the blog");
28db.Remove(blog);
29db.SaveChanges();
Si può osservare che il database è ritornato ad essere vuoto.
Come nell’esempio precedente, creiamo un progetto Console .NET Core
1# creiamo una nuova soluzione
2dotnet new sln -o GestioneFattureClienti
3# spostiamoci nella cartella della soluzione
4cd GestioneFattureClienti
5# creiamo un nuovo progetto di tipo console all'interno della soluzione
6dotnet new console -o GestioneFattureClienti
7# aggiungiamo il progetto alla soluzione
8dotnet sln add GestioneFattureClienti\GestioneFattureClienti.csproj
9# facciamo partire Visual Studio Code sulla soluzione
10code .
Dalla shell posizionata sulla cartella del progetto GestioneFattureClienti
, installiamo i seguenti pacchetti nel progetto:
1# installiamo il pacchetto Design
2# https://www.nuget.org/packages/microsoft.entityframeworkcore.design/
3dotnet add package Microsoft.EntityFrameworkCore.Design
4# installiamo il pacchetto per Sqlite
5# https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Sqlite
6dotnet add package Microsoft.EntityFrameworkCore.Sqlite
patcx.vscode-nuget-gallery
).In Visual Studio Code, tramite C# Dev Kit, creare la cartella Model
e al suo interno aggiungere la classe Cliente
nel file Cliente.cs
con il seguente codice:
1namespace GestioneFattureClienti.Model;
2public class Cliente
3{
4 public int ClienteId { get; set; }
5 public string RagioneSociale { get; set; } = null!;
6 public string PartitaIVA { get; set; } = null!;
7 public string? Citta { get; set; }
8 public string? Via { get; set; }
9 public string? Civico { get; set; }
10 public string? CAP { get; set; }
11 public List<Fattura> Fatture { get; } = [];
12
13 public override string ToString()
14 {
15 return $"{{{nameof(ClienteId)} = {ClienteId}, " +
16 $"{nameof(RagioneSociale)} = {RagioneSociale}, " +
17 $"{nameof(PartitaIVA)} = {PartitaIVA}, " +
18 $"{nameof(Citta)} = {Citta}, " +
19 $"{nameof(Via)} = {Via}, " +
20 $"{nameof(Civico)} = {Civico}, " +
21 $"{nameof(CAP)} = {CAP}}}";
22 }
23}
Aggiungere la classe Fattura
nel file Fattura.cs
all’interno della cartella Model
, con dentro il seguente codice:
1namespace GestioneFattureClienti.Model;
2
3public class Fattura
4{
5 public int FatturaId { get; set; }
6 public DateTime Data { get; set; }
7 public decimal Importo { get; set; }
8 public int ClienteId { get; set; }
9 public Cliente Cliente { get; set; } = null!;
10
11 public override string ToString()
12 {
13 return $"{{{nameof(FatturaId)} = {FatturaId}, " +
14 $"{nameof(Data)} = {Data.ToShortDateString()}, " +
15 $"{nameof(Importo)} = {Importo}, " +
16 $"{nameof(ClienteId)} = {ClienteId}}}";
17 }
18}
In Visual Studio Code, tramite C# Dev Kit, creare la cartella Data
e al suo interno aggiungere la classe FattureClientiContext
nel file FattureClientiContext.cs
con il codice:
1using GestioneFattureClienti.Model;
2using Microsoft.EntityFrameworkCore;
3namespace GestioneFattureClienti.Data;
4public class FattureClientiContext : DbContext
5{
6 public DbSet<Fattura> Fatture { get; set; } = null!;
7 public DbSet<Cliente> Clienti { get; set; } = null!;
8 public string DbPath { get; }
9
10 public FattureClientiContext()
11 {
12 //https://www.hanselman.com/blog/how-do-i-find-which-directory-my-net-core-console-application-was-started-in-or-is-running-from
13 var folder = AppContext.BaseDirectory;
14 //La BaseDirectory restituisce la cartella dove si trova l'assembly (.dll e .exe del programma compilato)
15 //il database, per comodità, è inserito nella cartella di progetto, dove si trova anche il file Program.cs
16 var path = Path.Combine(folder, "../../../FattureClienti.db");
17 DbPath = path;
18 }
19 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
20 => optionsBuilder.UseSqlite($"Data Source={DbPath}");
21}
A questo punto nel progetto dovrebbe essere presente una struttura di file e cartelle come quella riportata nella figura seguente:
Eseguire il seguente comando nella shell posizionata sulla cartella del progetto
1# effettuiamo la prima migrazione
2dotnet ef migrations add InitialCreate
3
4# creiamo il database a partire dalla migrazione
5dotnet ef database update
Una volta eseguita la migration e aggiornato il database, dovrebbe essere presente un file di database di SQLite FattureClienti.db
con le tabelle corrispondenti agli oggetti Fatture
e Clienti
(di tipo DBSet<Fattura>
e DBSet<Cliente>
rispettivamente).
Dopo aver eseguito la migration e l’aggiornamento del database, la struttura dei file e delle cartelle dovrebbe essere come quella della figura seguente:
Program
per testare le funzionalità di EF Core con SQLite, come nell’esempio seguente: 1using GestioneFattureClienti.Data;
2using System.Text;
3using GestioneFattureClienti.Model;
4using Microsoft.EntityFrameworkCore.Storage;
5using Microsoft.EntityFrameworkCore.Infrastructure;
6
7Console.OutputEncoding = Encoding.UTF8;
8Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo("it-IT");
9
10ModalitàOperativa modalitàOperativa = ModalitàOperativa.Nessuna;
11//colore di default della console
12Console.ForegroundColor = ConsoleColor.Cyan;
13//gestione del menu
14bool uscitaDalProgramma = false;
15do
16{
17 //gestione della scelta
18 bool correctInput = false;
19 do
20 {
21 Console.WriteLine("Inserire la modalità operativa [CreazioneDb, LetturaDb, ModificaFattura, CancellazioneFattura, CancellazioneDb, Nessuna]");
22 correctInput = Enum.TryParse(Console.ReadLine(), true, out modalitàOperativa);
23 if (correctInput)
24 {
25 switch (modalitàOperativa)
26 {
27 case ModalitàOperativa.CreazioneDb:
28 CreazioneDb();
29 break;
30 case ModalitàOperativa.LetturaDb:
31 LetturaDb();
32 break;
33 case ModalitàOperativa.ModificaFattura:
34 ModificaFattura();
35 break;
36 case ModalitàOperativa.CancellazioneFattura:
37 CancellazioneFattura();
38 break;
39 case ModalitàOperativa.CancellazioneDb:
40 CancellazioneDb();
41 break;
42 default:
43 WriteLineWithColor("Non è stata impostata nessuna modalità operativa", ConsoleColor.Yellow);
44 break;
45 }
46 }
47 if (!correctInput)
48 {
49 Console.Clear();
50 WriteLineWithColor("Il valore inserito non corrisponde a nessuna opzione valida.\nI valori ammessi sono: [Creazione, Lettura, Modifica, Cancellazione, Nessuna]", ConsoleColor.Red);
51 }
52 } while (!correctInput);
53 Console.WriteLine("Uscire dal programma?[Si, No]");
54 uscitaDalProgramma = Console.ReadLine()?.StartsWith("si", StringComparison.CurrentCultureIgnoreCase) ?? false;
55 Console.Clear();
56} while (!uscitaDalProgramma);
57
58static void CreazioneDb()
59{
60 using FattureClientiContext db = new();
61 //verifichiamo se il database esista già
62 //https://medium.com/@Usurer/ef-core-check-if-db-exists-feafe6e36f4e
63 //https://stackoverflow.com/questions/33911316/entity-framework-core-how-to-check-if-database-exists
64 if (db.Database.GetService<IRelationalDatabaseCreator>().Exists())
65 {
66 WriteLineWithColor("Il database esiste già, vuoi ricrearlo da capo? Tutti i valori precedentemente inseriti verranno persi. [Si, No]", ConsoleColor.Red);
67 bool dbErase = Console.ReadLine()?.StartsWith("si", StringComparison.CurrentCultureIgnoreCase) ?? false;
68 if (dbErase)
69 {
70 //cancelliamo il database se esiste
71 db.Database.EnsureDeleted();
72 //ricreiamo il database a partire dal model (senza dati --> tabelle vuote)
73 db.Database.EnsureCreated();
74 //inseriamo i dati nelle tabelle
75 PopulateDb(db);
76 }
77 }
78 else //il database non esiste
79 {
80 //ricreiamo il database a partire dal model (senza dati --> tabelle vuote)
81 db.Database.EnsureCreated();
82 //popoliamo il database
83 PopulateDb(db);
84 }
85
86 static void PopulateDb(FattureClientiContext db)
87 {
88 //Creazione dei Clienti - gli id vengono generati automaticamente come campi auto-incremento quando si effettua l'inserimento, tuttavia
89 //è bene inserire esplicitamente l'id degli oggetti quando si procede all'inserimento massivo gli elementi mediante un foreach perché
90 //EF core potrebbe inserire nel database gli oggetti in un ordine diverso rispetto a quello del foreach
91 // https://stackoverflow.com/a/54692592
92 // https://stackoverflow.com/questions/11521057/insertion-order-of-multiple-records-in-entity-framework/
93 List<Cliente> listaClienti =
94 [
95 new (){ClienteId=1, RagioneSociale= "Cliente 1", PartitaIVA= "1111111111", Citta = "Napoli", Via="Via dei Mille", Civico= "23", CAP="80100"},
96 new (){ClienteId=2, RagioneSociale= "Cliente 2", PartitaIVA= "1111111112", Citta = "Roma", Via="Via dei Fori Imperiali", Civico= "1", CAP="00100"},
97 new (){ClienteId=3, RagioneSociale= "Cliente 3", PartitaIVA= "1111111113", Citta = "Firenze", Via="Via Raffaello", Civico= "10", CAP="50100"}
98 ];
99
100 //Creazione delle Fatture
101 List<Fattura> listaFatture =
102 [
103 new (){FatturaId=1, Data= DateTime.Now.Date, Importo = 1200.45m, ClienteId = 1},
104 new (){FatturaId=2, Data= DateTime.Now.AddDays(-5).Date, Importo = 3200.65m, ClienteId = 1},
105 new (){FatturaId=3, Data= new DateTime(2019,10,20).Date, Importo = 5200.45m, ClienteId = 1},
106 new (){FatturaId=4, Data= DateTime.Now.Date, Importo = 5200.45m, ClienteId = 2},
107 new (){FatturaId=5, Data= new DateTime(2019,08,20).Date, Importo = 7200.45m, ClienteId = 2}
108 ];
109 Console.WriteLine("Inseriamo i clienti nel database");
110 listaClienti.ForEach(c => db.Add(c));
111 db.SaveChanges();
112 Console.WriteLine("Inseriamo le fatture nel database");
113 listaFatture.ForEach(f => db.Add(f));
114 db.SaveChanges();
115 }
116}
117
118static void LetturaDb()
119{
120 //recuperiamo i dati dal database
121 using FattureClientiContext db = new();
122 //Nel caso in cui il database fosse stato eliminato ricreiamo un nuovo database vuoto a partire dal Model
123 db.Database.EnsureCreated();
124 //Il codice seguente è scritto in modo che se anche non ci fossero dati nelle tabelle non verrebbero sollevate eccezioni
125 Console.WriteLine("Recuperiamo i dati dal database - senza alcuna elaborazione");
126 List<Cliente> listaClienti = [.. db.Clienti];
127 List<Fattura> listaFatture = [.. db.Fatture];
128 Console.WriteLine("Stampa dei clienti");
129 listaClienti.ForEach(Console.WriteLine);
130 Console.WriteLine("Stampa delle fatture");
131 listaFatture.ForEach(Console.WriteLine);
132
133 Console.WriteLine("Recuperiamo i dati dal database - uso di WHERE");
134 Console.WriteLine("Recuperiamo i dati dal database - trovare le fatture fatte da almeno tre giorni");
135 db.Fatture.Where(f => f.Data < DateTime.Now.AddDays(-2)).ToList().ForEach(f => Console.WriteLine(f));
136
137 Console.WriteLine("Recuperiamo i dati dal database - trovare l'importo complessivo delle fatture fatte da almeno tre giorni ");
138 Console.WriteLine($"Importo complessivo: {db.Fatture.Where(f => f.Data < DateTime.Now.AddDays(-2)).Sum(f => (double)f.Importo):C2}");
139
140 Console.WriteLine("Recuperiamo i dati dal database - trovare l'importo medio delle fatture fatte da almeno tre giorni ");
141 //troviamo prima di tutto quante sono le fatture
142 static bool searchPredicate(Fattura f) => f.Data < DateTime.Now.AddDays(-2);
143 var count = db.Fatture.Where(searchPredicate).Count();
144
145 //se non ci sono elementi nella collection i metodi Average, Max e Min sollevano l'eccezione InvalidOperationException
146 if (count > 0)
147 {
148 Console.WriteLine($"Importo medio: {db.Fatture.Where(searchPredicate).Average(f => (double)f.Importo):C2}");
149 Console.WriteLine("Recuperiamo i dati dal database - trovare l'importo massimo delle fatture fatte da almeno tre giorni ");
150 Console.WriteLine($"Importo massimo: {db.Fatture.Where(searchPredicate).Max(f => (double)f.Importo):C2}");
151 Console.WriteLine("Recuperiamo i dati dal database - trovare l'importo minimo delle fatture fatte da almeno tre giorni ");
152 Console.WriteLine($"Importo minimo: {db.Fatture.Where(searchPredicate).Min(f => (double)f.Importo):C2}");
153 Console.WriteLine("Recuperiamo i dati dal database - trovare il numero delle fatture fatte da almeno tre giorni ");
154 Console.WriteLine("Numero fatture: " + count);
155 }
156 Console.WriteLine("Recuperiamo i dati dal database - uso di WHERE e JOIN");
157 Console.WriteLine("trovare il nome e l'indirizzo dei clienti che hanno speso più di 5000 EUR");
158 var clientiConSpesa5000Plus =
159 db.Fatture
160 .Where(f => f.Importo > 5000)
161 .Join(db.Clienti,
162 f => f.ClienteId,
163 c => c.ClienteId,
164 (f, c) => new { NumeroFattura = f.FatturaId, DataFattura = f.Data, NomeCliente = c.RagioneSociale, Indirizzo = c.Via + " N." + c.Civico + " " + c.CAP + " " + c.Citta });
165 clientiConSpesa5000Plus.ToList().ForEach(Console.WriteLine);
166
167 //altro modo - uso delle navigation properties
168 Console.WriteLine("Recuperiamo i dati dal database - Uso di Navigation Property per ottenere i dati dei clienti a partire dalle fatture");
169 var clientiConSpesa5000Plus2 =
170 db.Fatture
171 .Where(f => f.Importo > 5000)
172 .Select(f => new
173 {
174 NumeroFattura = f.FatturaId,
175 DataFattura = f.Data,
176 NomeCliente = f.Cliente.RagioneSociale,
177 Indirizzo = f.Cliente.Via + " N." + f.Cliente.Civico + " " + f.Cliente.CAP + " " + f.Cliente.Citta
178 });
179 clientiConSpesa5000Plus2.ToList().ForEach(Console.WriteLine);
180}
181
182static void ModificaFattura()
183{
184 using FattureClientiContext db = new();
185 //la modifica ha senso solo se il database esiste e ha almeno un paio di fatture inserite
186 //Nel caso in cui il database fosse stato eliminato ricreiamo un nuovo database vuoto a partire dal Model
187 db.Database.EnsureCreated();
188 //Il codice seguente è scritto in modo che se anche non ci fossero dati nelle tabelle non verrebbero sollevate eccezioni
189 var numeroFatture = db.Fatture.Count();
190 if (numeroFatture > 2)
191 {
192 Console.WriteLine("\nModifichiamo i dati nel database");
193 Console.WriteLine("Modifichiamo l'importo della prima fattura");
194
195 Console.WriteLine("\nle fatture prima della modifica sono:\n");
196
197 //stampiamo la lista delle fatture per vedere il risultato
198 //se il database non esiste listaFatture sarà null.
199
200 List<Fattura> listaFatture = db.Fatture.ToList();
201 Console.WriteLine("Stampa delle fatture");
202 listaFatture.ForEach(f => Console.WriteLine(f));
203
204 //accediamo all'elemento da modificare
205 Fattura? fattura = db.Fatture.Find(1);//trova l'entity con il valore della chiave (FatturaId) specificato
206 if (fattura != null)//se ho trovato la fattura con FatturaId specificato
207 {
208 //modifichiamo la fattura
209 fattura.Importo *= 1.2m;//incremento del 20% l'importo
210 db.SaveChanges();//aggiorno il database
211
212 //stampiamo la lista delle fatture per vedere il risultato
213 listaFatture = [.. db.Fatture];
214 Console.WriteLine("Stampa delle fatture dopo la modifica");
215 listaFatture.ForEach(Console.WriteLine);
216 }
217 Console.WriteLine("\nmodifichiamo anche la seconda fattura");
218 //non è possibile usare ElementAt - https://stackoverflow.com/questions/5147767/why-is-the-query-operator-elementat-is-not-supported-in-linq-to-sql
219 Fattura? secondaFattura = db.Fatture.Skip(1)?.First();
220 if (secondaFattura != null)
221 {
222 secondaFattura.Importo *= 1.3m;
223 db.SaveChanges();
224 //stampiamo la lista delle fatture per vedere il risultato
225 listaFatture = [.. db.Fatture];
226 Console.WriteLine("Stampa delle fatture");
227 listaFatture.ForEach(Console.WriteLine);
228 }
229 Console.WriteLine("\nmodifichiamo anche l'ultima");
230 //non è possibile usare ElementAt - https://stackoverflow.com/questions/5147767/why-is-the-query-operator-elementat-is-not-supported-in-linq-to-sql
231 Fattura? ultimaFattura = db.Fatture.OrderBy(f => f.FatturaId).Last();
232 if (ultimaFattura != null)
233 {
234 ultimaFattura.Importo *= 1.5m;
235 db.SaveChanges();
236 //stampiamo la lista delle fatture per vedere il risultato
237 listaFatture = db.Fatture.ToList();
238 Console.WriteLine("Stampa delle fatture");
239 listaFatture.ForEach(f => Console.WriteLine(f));
240 }
241 }
242 else
243 {
244 WriteLineWithColor("Non ci sono abbastanza Fatture nel database per eseguire la funzionalità richiesta", ConsoleColor.Red);
245 }
246}
247static void CancellazioneFattura()
248{
249 using FattureClientiContext db = new();
250 //Nel caso in cui il database fosse stato eliminato ricreiamo un nuovo database vuoto a partire dal Model
251 db.Database.EnsureCreated();
252 //Il codice seguente è scritto in modo che se anche non ci fossero dati nelle tabelle non verrebbero sollevate eccezioni
253 Console.WriteLine("\nEliminiamo un dato dal database");
254 Console.WriteLine("\nPrima della cancellazione le fatture sono:");
255 List<Fattura> listaFatture = [.. db.Fatture];
256 Console.WriteLine("Stampa delle fatture");
257 listaFatture.ForEach(Console.WriteLine);
258 Console.WriteLine("\nEliminiamo la terza fattura");
259 //accediamo alla terza fattura - possiamo accedere mediante chiave, oppure in base ad un elenco da cui prendiamo la terza fattura
260 //decidiamo di eliminare la fattura con FatturaId=3
261 Fattura? fatturaDaEliminare = db.Fatture.Find(3);
262 if (fatturaDaEliminare != null)//se abbiamo trovato la fattura con id =3
263 {
264 Console.WriteLine($"eliminiamo la fattura con id {fatturaDaEliminare.FatturaId}");
265 db.Remove(fatturaDaEliminare);
266 db.SaveChanges();
267 //stampiamo nuovamente l'elenco delle fatture per verificare che la fattura con id specifico è stata eliminata
268 listaFatture = [.. db.Fatture];
269 Console.WriteLine("Stampa delle fatture");
270 listaFatture.ForEach(Console.WriteLine);
271 }
272 else
273 {
274 WriteLineWithColor("Non è stato possibile eliminare la fattura indicata, perché non esiste", ConsoleColor.Red);
275 }
276}
277
278static void CancellazioneDb()
279{
280 using FattureClientiContext db = new();
281 WriteLineWithColor("Attenzione tutto il database andrà eliminato! Questa operazione non può essere revocata.\nSei sicuro di voler procedere? [Si, No]", ConsoleColor.Red);
282 bool dbErase = Console.ReadLine()?.StartsWith("si", StringComparison.CurrentCultureIgnoreCase) ?? false;
283 if (dbErase)
284 {
285 if (db.Database.EnsureDeleted())
286 {
287 Console.WriteLine("Database cancellato correttamente");
288 }
289 else
290 {
291 Console.WriteLine("Il database non esisteva e non è stata fatta alcuna azione");
292 }
293 }
294}
295
296//stampa a console con il colore di foreground selezionato e successivamente ripristina il colore precedente
297static void WriteLineWithColor(string text, ConsoleColor consoleColor)
298{
299 ConsoleColor previousColor = Console.ForegroundColor;
300 Console.ForegroundColor = consoleColor;
301 Console.WriteLine(text);
302 Console.ForegroundColor = previousColor;
303}
304enum ModalitàOperativa
305{
306 CreazioneDb,
307 LetturaDb,
308 ModificaFattura,
309 CancellazioneFattura,
310 CancellazioneDb,
311 Nessuna
312}