Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här stegvisa genomgången visar hur du skapar ett enkelt Windows Forms-program (WinForms) som backas upp av en SQLite-databas. Programmet använder Entity Framework Core (EF Core) för att läsa in data från databasen, spåra ändringar som gjorts i dessa data och spara ändringarna i databasen igen.
Skärmbilderna och kodlistorna i den här genomgången tas från Visual Studio 2022 17.3.0.
Tips/Råd
Du kan visa den här artikelns exempel på GitHub.
Förutsättningar
Du måste ha Visual Studio 2022 17.3 eller senare installerat med .NET Desktop-arbetsbelastningen vald för att slutföra den här genomgången. Mer information om hur du installerar den senaste versionen av Visual Studio finns i Installera Visual Studio.
Skapa programmet
Öppna Visual Studio
I startfönstret väljer du Skapa nytt projekt.
Välj Windows Forms App och välj sedan Nästa.
På nästa skärm ger du projektet ett namn, till exempel GetStartedWinForms, och väljer Nästa.
På nästa skärm väljer du den .NET-version som ska användas. Den här genomgången skapades med .NET 7, men den bör också fungera med senare versioner.
Välj Skapa.
Installera EF Core NuGet-paket
Högerklicka på lösningen och välj Hantera NuGet-paket för lösning...
Välj fliken Bläddra och sök efter "Microsoft.EntityFrameworkCore.Sqlite".
Välj paketet Microsoft.EntityFrameworkCore.Sqlite .
Kontrollera projektet GetStartedWinForms i den högra rutan.
Välj den senaste versionen. Om du vill använda en förhandsversion kontrollerar du att rutan Inkludera förhandsversion är markerad.
Klicka på Installera
Anmärkning
Microsoft.EntityFrameworkCore.Sqlite är paketet "databasprovider" för användning av EF Core med en SQLite-databas. Liknande paket är tillgängliga för andra databassystem. När du installerar ett databasproviderpaket får du automatiskt in alla beroenden som krävs för att använda EF Core med det databassystemet. Detta inkluderar baspaketet Microsoft.EntityFrameworkCore .
Definiera en modell
I den här genomgången implementerar vi en modell med hjälp av "Code First". Det innebär att EF Core skapar databastabellerna och schemat baserat på de C#-klasser som du definierar. Se Hantera databasscheman för att se hur du använder en befintlig databas i stället.
Högerklicka på projektet och välj Lägg till och sedan Klass... för att lägga till en ny klass.
Använd filnamnet
Product.csoch ersätt koden för klassen med:using System.ComponentModel; namespace GetStartedWinForms; public class Product { public int ProductId { get; set; } public string? Name { get; set; } public int CategoryId { get; set; } public virtual Category Category { get; set; } = null!; }Upprepa för att skapa
Category.csmed följande kod:using Microsoft.EntityFrameworkCore.ChangeTracking; namespace GetStartedWinForms; public class Category { public int CategoryId { get; set; } public string? Name { get; set; } public virtual ObservableCollectionListSource<Product> Products { get; } = new(); }
Egenskapen Products för Category klassen och Category egenskapen i Product klassen kallas "navigering". I EF Core definierar navigering en relation mellan två entitetstyper. I det här fallet refererar navigeringen Product.Category till den kategori som en viss produkt tillhör.
Category.Products På samma sätt innehåller samlingsnavigering alla produkter för en viss kategori.
Tips/Råd
När du använder Windows Forms kan ObservableCollectionListSource, som implementerar IListSource, användas för samlingars navigering. Detta är inte nödvändigt, men det förbättrar upplevelsen av dubbelriktad databindning.
Definiera DbContext
I EF Core används en klass som härleds från DbContext för att konfigurera entitetstyper i en modell och fungera som en session för att interagera med databasen. I det enklaste fallet är en DbContext klass:
- Innehåller
DbSetegenskaper för varje entitetstyp i modellen. - Åsidosätter
OnConfiguringmetoden för att konfigurera databasprovidern och anslutningssträngen som ska användas. Mer information finns i Konfigurera en DbContext .
I det här fallet åsidosätter OnModelCreating klassen DbContext även metoden för att tillhandahålla exempeldata för programmet.
Lägg till en ny ProductsContext.cs klass i projektet med följande kod:
using Microsoft.EntityFrameworkCore;
namespace GetStartedWinForms;
public class ProductsContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite("Data Source=products.db");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>().HasData(
new Category { CategoryId = 1, Name = "Cheese" },
new Category { CategoryId = 2, Name = "Meat" },
new Category { CategoryId = 3, Name = "Fish" },
new Category { CategoryId = 4, Name = "Bread" });
modelBuilder.Entity<Product>().HasData(
new Product { ProductId = 1, CategoryId = 1, Name = "Cheddar" },
new Product { ProductId = 2, CategoryId = 1, Name = "Brie" },
new Product { ProductId = 3, CategoryId = 1, Name = "Stilton" },
new Product { ProductId = 4, CategoryId = 1, Name = "Cheshire" },
new Product { ProductId = 5, CategoryId = 1, Name = "Swiss" },
new Product { ProductId = 6, CategoryId = 1, Name = "Gruyere" },
new Product { ProductId = 7, CategoryId = 1, Name = "Colby" },
new Product { ProductId = 8, CategoryId = 1, Name = "Mozzela" },
new Product { ProductId = 9, CategoryId = 1, Name = "Ricotta" },
new Product { ProductId = 10, CategoryId = 1, Name = "Parmesan" },
new Product { ProductId = 11, CategoryId = 2, Name = "Ham" },
new Product { ProductId = 12, CategoryId = 2, Name = "Beef" },
new Product { ProductId = 13, CategoryId = 2, Name = "Chicken" },
new Product { ProductId = 14, CategoryId = 2, Name = "Turkey" },
new Product { ProductId = 15, CategoryId = 2, Name = "Prosciutto" },
new Product { ProductId = 16, CategoryId = 2, Name = "Bacon" },
new Product { ProductId = 17, CategoryId = 2, Name = "Mutton" },
new Product { ProductId = 18, CategoryId = 2, Name = "Pastrami" },
new Product { ProductId = 19, CategoryId = 2, Name = "Hazlet" },
new Product { ProductId = 20, CategoryId = 2, Name = "Salami" },
new Product { ProductId = 21, CategoryId = 3, Name = "Salmon" },
new Product { ProductId = 22, CategoryId = 3, Name = "Tuna" },
new Product { ProductId = 23, CategoryId = 3, Name = "Mackerel" },
new Product { ProductId = 24, CategoryId = 4, Name = "Rye" },
new Product { ProductId = 25, CategoryId = 4, Name = "Wheat" },
new Product { ProductId = 26, CategoryId = 4, Name = "Brioche" },
new Product { ProductId = 27, CategoryId = 4, Name = "Naan" },
new Product { ProductId = 28, CategoryId = 4, Name = "Focaccia" },
new Product { ProductId = 29, CategoryId = 4, Name = "Malted" },
new Product { ProductId = 30, CategoryId = 4, Name = "Sourdough" },
new Product { ProductId = 31, CategoryId = 4, Name = "Corn" },
new Product { ProductId = 32, CategoryId = 4, Name = "White" },
new Product { ProductId = 33, CategoryId = 4, Name = "Soda" });
}
}
Kom ihåg att skapa lösningen just nu.
Lägga till kontroller i formuläret
Programmet visar en lista över kategorier och en lista över produkter. När en kategori väljs i den första listan ändras den andra listan för att visa produkter för den kategorin. Dessa listor kan ändras för att lägga till, ta bort eller redigera produkter och kategorier, och dessa ändringar kan sparas i SQLite-databasen genom att klicka på knappen Spara .
Ändra namnet på huvudformuläret från
Form1tillMainForm.
Och ändra rubriken till "Produkter och kategorier".
Med hjälp av verktygslådan lägger du till två
DataGridViewkontroller, ordnade bredvid varandra.
I Egenskaper för den första
DataGridViewändrar du Namnet tilldataGridViewCategories.I Egenskaper för den andra
DataGridViewändrar du Namnet tilldataGridViewProducts.Lägg även till en kontroll med hjälp av
Button.Namnge knappen
buttonSaveoch ge den texten "Spara". Formuläret bör se ut ungefär så här:
Datalänkning
Nästa steg är att ansluta typerna Product och Category från modellen till DataGridView kontrollerna. Detta binder data som läses in av EF Core till kontrollerna, så att de entiteter som spåras av EF Core hålls synkroniserade med dem som visas i kontrollerna.
Klicka på Designerens åtgärdsikon på den första
DataGridView. Det här är den lilla knappen i kontrollens övre högra hörn.
Då öppnas åtgärdslistan, från vilken listrutan för Välj datakälla kan nås. Vi har inte skapat någon datakälla än, så gå till botten och välj Lägg till ny objektdatakälla....
Välj Kategori för att skapa en objektdatakälla för kategorier och klicka på OK.
Tips/Råd
Om inga typer av datakällor visas här kontrollerar du att
Product.cs,Category.csochProductsContext.cshar lagts till i projektet och att lösningen har skapats.Listrutan Välj datakälla innehåller nu den objektdatakälla som vi nyss skapade. Expandera Andra datakällor, sedan Projektdatakällor och välj Kategori.
Den andra
DataGridViewkommer att bindas till produkter. Men istället för att binda till den övergripande nivånProduct, kommer den att bindas till navigeringenProducts, utifrån bindningenCategoryav den förstaDataGridView. Det innebär att när en kategori väljs i den första vyn används produkterna för den kategorin automatiskt i den andra vyn.Med hjälp av designeråtgärden glyph på den andra
DataGridViewväljer du Välj datakälla och expanderarcategoryBindingSourcesedan och väljerProducts.
Konfigurera vad som visas
Som standard skapas en kolumn i DataGridView för varje egenskap för de bundna typerna. Dessutom kan värdena för var och en av dessa egenskaper redigeras av användaren. Vissa värden, till exempel de primära nyckelvärdena, är dock begreppsmässigt skrivskyddade och bör därför inte redigeras. Dessutom är vissa egenskaper, till exempel CategoryId egenskapen för sekundärnyckel och navigeringen Category inte användbara för användaren, och bör därför vara dolda.
Tips/Råd
Det är vanligt att dölja primärnyckelegenskaper i ett verkligt program. De lämnas synliga här för att göra det enkelt att se vad EF Core gör i bakgrunden.
Högerklicka på den första
DataGridViewoch välj Redigera kolumner....
Gör kolumnen
CategoryId, som representerar den primära nyckeln, skrivskyddad och klicka på OK.
Högerklicka på den andra
DataGridViewoch välj Redigera kolumner....ProductIdGör kolumnen skrivskyddad och ta bort kolumnernaCategoryIdochCategoryoch klicka sedan på OK.
Ansluta till EF Core
Programmet behöver nu en liten mängd kod för att ansluta EF Core till de databundna kontrollerna.
MainFormÖppna koden genom att högerklicka på filen och välja Visa kod.
Lägg till ett privat fält för att lagra
DbContextför sessionen, och lägg till överskrivningar förOnLoadochOnClosingmetoderna. Koden bör se ut så här:
using Microsoft.EntityFrameworkCore;
using System.ComponentModel;
namespace GetStartedWinForms
{
public partial class MainForm : Form
{
private ProductsContext? dbContext;
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.dbContext = new ProductsContext();
// Uncomment the line below to start fresh with a new database.
// this.dbContext.Database.EnsureDeleted();
this.dbContext.Database.EnsureCreated();
this.dbContext.Categories.Load();
this.categoryBindingSource.DataSource = dbContext.Categories.Local.ToBindingList();
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
this.dbContext?.Dispose();
this.dbContext = null;
}
}
}
Metoden OnLoad anropas när formuläret läses in. Just nu
- En instans av
ProductsContextskapas som ska användas för att läsa in och spåra ändringar av produkter och kategorier som visas av programmet. -
EnsureCreatedanropas påDbContextför att skapa SQLite-databasen om den inte redan finns. Det här är ett snabbt sätt att skapa en databas vid prototyper eller testning av program. Men om modellen ändras måste databasen tas bort så att den kan skapas igen. (RadenEnsureDeletedkan inte kommenteras för att enkelt ta bort och återskapa databasen när programmet körs.) Du kanske i stället vill använda EF Core-migreringar för att ändra och uppdatera databasschemat utan att förlora några data. -
EnsureCreatedfyller också i den nya databasen med de data som definierats iProductsContext.OnModelCreatingmetoden. - Tilläggsmetoden
Loadanvänds för att läsa in alla kategorier från databasen tillDbContext. Dessa entiteter spåras nu avDbContext, som identifierar eventuella ändringar som görs när kategorierna redigeras av användaren. - Egenskapen
categoryBindingSource.DataSourceinitialiseras med de kategorier som spåras avDbContext. Detta görs genom att anropaLocal.ToBindingList()egenskapenCategoriesDbSet.Localger åtkomst till en lokal vy över de spårade kategorierna, med händelser kopplade för att säkerställa att lokala data förblir synkroniserade med de data som visas och vice versa.ToBindingList()exponerar dessa data som enIBindingList, vilket förstås av Databindningen i Windows Forms.
Metoden OnClosing anropas när formuläret stängs. För närvarande DbContext tas bort, vilket säkerställer att alla databasresurser frigörs, och dbContext fältet är inställt på null så att det inte kan användas igen.
Fylla Produkter-vyn
Om programmet startas nu bör det se ut ungefär så här:
Observera att kategorierna har lästs in från databasen, men produkttabellen förblir tom. Knappen Spara fungerar inte heller.
För att fylla i produkttabellen måste EF Core läsa in produkter från databasen för den valda kategorin. För att åstadkomma detta:
I designern för huvudformuläret väljer du kategorier med
DataGridView.I Egenskaper för
DataGridViewväljer du händelserna (blixtknappen) och dubbelklickar på händelsen SelectionChanged .
Detta skapar stub i huvudformulärkoden för en händelse som ska utlöses när kategorivalet ändras.
Fyll i koden för händelsen:
private void dataGridViewCategories_SelectionChanged(object sender, EventArgs e)
{
if (this.dbContext != null)
{
var category = (Category)this.dataGridViewCategories.CurrentRow.DataBoundItem;
if (category != null)
{
this.dbContext.Entry(category).Collection(e => e.Products).Load();
}
}
}
Om det finns en aktiv (icke-null) DbContext -session i den här koden hämtar vi den Category instans som är bunden till den markerade raden i DataViewGrid. (Detta kan vara null om den sista raden i vyn är markerad, som används för att skapa nya kategorier.) Om det finns en vald kategori DbContext instrueras du att läsa in de produkter som är associerade med den kategorin. Detta görs genom att:
- Hämta en
EntityEntryför instansenCategory(dbContext.Entry(category)) - Att låta EF Core veta att vi vill arbeta med kollektionsnavigeringen för
ProductsiCategory(.Collection(e => e.Products)) - Och slutligen berätta för EF Core att vi vill läsa in den samlingen av produkter från databasen (
.Load();)
Tips/Råd
När Load anropas kommer EF Core bara åt databasen för att läsa in produkterna om de inte redan har lästs in.
Om programmet nu körs igen bör det läsa in lämpliga produkter när en kategori har valts:
Spara ändringar
Slutligen kan knappen Spara anslutas till EF Core så att alla ändringar som görs i produkterna och kategorierna sparas i databasen.
I designern för huvudformuläret väljer du knappen Spara .
I Egenskaper för
Buttonväljer du händelserna (blixtknappen) och dubbelklickar på händelsen Klicka .
Fyll i koden för händelsen:
private void buttonSave_Click(object sender, EventArgs e)
{
this.dbContext!.SaveChanges();
this.dataGridViewCategories.Refresh();
this.dataGridViewProducts.Refresh();
}
Den här koden anropar SaveChanges på DbContext, som sparar alla ändringar som gjorts i SQLite-databasen. Om inga ändringar har gjorts är det här en no-opoch inget databasanrop görs. Efter att DataGridView har sparats, uppdateras kontrollerna. Det beror på att EF Core läser genererade primära nyckelvärden för alla nya produkter och kategorier från databasen. Anropet Refresh uppdaterar visningen med dessa genererade värden.
Den slutliga ansökan
Här är den fullständiga koden för huvudformuläret:
using Microsoft.EntityFrameworkCore;
using System.ComponentModel;
namespace GetStartedWinForms
{
public partial class MainForm : Form
{
private ProductsContext? dbContext;
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.dbContext = new ProductsContext();
// Uncomment the line below to start fresh with a new database.
// this.dbContext.Database.EnsureDeleted();
this.dbContext.Database.EnsureCreated();
this.dbContext.Categories.Load();
this.categoryBindingSource.DataSource = dbContext.Categories.Local.ToBindingList();
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
this.dbContext?.Dispose();
this.dbContext = null;
}
private void dataGridViewCategories_SelectionChanged(object sender, EventArgs e)
{
if (this.dbContext != null)
{
var category = (Category)this.dataGridViewCategories.CurrentRow.DataBoundItem;
if (category != null)
{
this.dbContext.Entry(category).Collection(e => e.Products).Load();
}
}
}
private void buttonSave_Click(object sender, EventArgs e)
{
this.dbContext!.SaveChanges();
this.dataGridViewCategories.Refresh();
this.dataGridViewProducts.Refresh();
}
}
}
Programmet kan nu köras och produkter och kategorier kan läggas till, tas bort och redigeras. Observera att om knappen Spara klickas innan programmet stängs lagras alla ändringar som görs i databasen och läses in igen när programmet startas på nytt. Om Spara inte klickas går alla ändringar förlorade när programmet startas på nytt.
Tips/Råd
En ny kategori eller produkt kan läggas till i en DataViewControl med hjälp av den tomma raden längst ned i kontrollen. Du kan ta bort en rad genom att markera den och trycka på Del-tangenten .
Innan du sparar
När du har sparat
Observera att de primära nyckelvärdena för den tillagda kategorin och produkterna fylls i när Spara klickas.
Lära sig mer
- Konfigurering av en DbContext
- Skapa och konfigurera en modell
- Hantera databasscheman
- Fråga data
- ändringsspårning
- Spara data
- Databindning med OOP Windows Forms Designer