Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym przewodniku krok po kroku pokazano, jak utworzyć prostą aplikację Windows Forms (WinForms) wspieraną przez bazę danych SQLite. Aplikacja używa programu Entity Framework Core (EF Core) do ładowania danych z bazy danych, śledzenia zmian wprowadzonych w tych danych i utrwalania tych zmian z powrotem w bazie danych.
Zrzuty ekranu i listy kodu w tym przewodniku pochodzą z programu Visual Studio 2022 17.3.0.
Wskazówka
Przykład z tego artykułu można zobaczyć w witrynie GitHub.
Wymagania wstępne
Aby ukończyć ten przewodnik, musisz mieć zainstalowany program Visual Studio 2022 w wersji 17.3 lub nowszej z obciążeniem pulpitu platformy .NET. Aby uzyskać więcej informacji na temat instalowania najnowszej wersji programu Visual Studio, zobacz Instalowanie programu Visual Studio.
Tworzenie aplikacji
Otwórz program Visual Studio.
W oknie uruchamiania wybierz pozycję Utwórz nowy projekt.
Wybierz pozycję Aplikacja Windows Forms, a następnie wybierz pozycję Dalej.
Na następnym ekranie nadaj projektowi nazwę, na przykład GetStartedWinForms, a następnie wybierz pozycję Dalej.
Na następnym ekranie wybierz wersję platformy .NET do użycia. Ten przewodnik został utworzony za pomocą platformy .NET 7, ale powinien również pracować z nowszymi wersjami.
Wybierz pozycję Utwórz.
Instalowanie pakietów NuGet platformy EF Core
Kliknij rozwiązanie prawym przyciskiem myszy i wybierz polecenie Zarządzaj pakietami NuGet dla rozwiązania...
Zarządzanie pakietami NuGet dla rozwiązania
Wybierz kartę Przeglądaj i wyszukaj frazę "Microsoft.EntityFrameworkCore.Sqlite".
Wybierz pakiet Microsoft.EntityFrameworkCore.Sqlite.
Sprawdź projekt GetStartedWinForms w okienku po prawej stronie.
Wybierz najnowszą wersję. Aby użyć wersji wstępnej, upewnij się, że pole Uwzględnij wersję wstępną jest zaznaczone.
Kliknij pozycję Zainstaluj
Uwaga
Microsoft.EntityFrameworkCore.Sqlite to pakiet "dostawca bazy danych" do korzystania z programu EF Core z bazą danych SQLite. Podobne pakiety są dostępne dla innych systemów baz danych. Zainstalowanie pakietu dostawcy bazy danych automatycznie wprowadza wszystkie zależności potrzebne do korzystania z programu EF Core z tym systemem bazy danych. To obejmuje pakiet podstawowy Microsoft.EntityFrameworkCore.
Definiowanie modelu
W tym tutorialu zaimplementujemy model przy użyciu podejścia "Code First". Oznacza to, że program EF Core utworzy tabele i schemat bazy danych na podstawie zdefiniowanych klas języka C#. Zobacz Zarządzanie schematami baz danych, aby zobaczyć, jak zamiast tego używać istniejącej bazy danych.
Kliknij prawym przyciskiem myszy projekt i wybierz polecenie Dodaj, a następnie pozycję Klasa... , aby dodać nową klasę.
Użyj nazwy pliku
Product.csi zastąp kod klasy: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!; }Powtórz, aby utworzyć
Category.csprzy użyciu następującego kodu.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(); }
Właściwość Products klasy Category oraz właściwość Category klasy Product nazywa się "nawigacjami". W programie EF Core nawigacje definiują relację między dwoma typami jednostek. W takim przypadku nawigacja Product.Category odwołuje się do kategorii, do której należy dany produkt. Podobnie nawigacja Category.Products po kolekcji zawiera wszystkie produkty dla danej kategorii.
Wskazówka
Podczas korzystania z Windows Forms, ObservableCollectionListSource, który implementuje IListSource, może być używany do nawigacji w ramach kolekcji. Nie jest to konieczne, ale poprawia doświadczenie związane z dwukierunkowym powiązaniem danych.
Definiowanie elementu DbContext
W programie EF Core klasa pochodna DbContext jest używana do konfigurowania typów jednostek w modelu i działania jako sesji interakcji z bazą danych. W najprostszym przypadku klasa DbContext:
- Zawiera
DbSetwłaściwości dla każdego typu jednostki w modelu. - Nadpisuje metodę, aby skonfigurować dostawcę bazy danych
OnConfiguringi łańcuch połączenia, które mają być używane. Aby uzyskać więcej informacji, zobacz Konfigurowanie elementu DbContext .
W tym przypadku klasa DbContext zastępuje również metodę OnModelCreating w celu dostarczenia przykładowych danych dla aplikacji.
Dodaj nową ProductsContext.cs klasę do projektu przy użyciu następującego kodu:
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" });
}
}
Upewnij się, że w tym momencie skompiluj rozwiązanie .
Dodawanie kontrolek do formularza
Aplikacja wyświetli listę kategorii i listę produktów. Po wybraniu kategorii na pierwszej liście druga lista zmieni się, aby wyświetlić produkty dla tej kategorii. Te listy można modyfikować w celu dodawania, usuwania lub edytowania produktów i kategorii, a te zmiany można zapisać w bazie danych SQLite, klikając przycisk Zapisz .
Zmień nazwę formularza głównego z
Form1naMainForm.
Zmień tytuł na "Produkty i kategorie".
Używając przybornika , dodaj dwie kontrolki
DataGridView, ułożone obok siebie.
W właściwości dla pierwszego
DataGridViewelementu zmień nazwę nadataGridViewCategories.W obszarze Właściwości dla drugiego
DataGridViewelementu zmień nazwę nadataGridViewProducts.Korzystając także z Toolbox, dodaj kontrolkę
Button.Nadaj przyciskowi
buttonSavenazwę i nadaj mu tekst "Zapisz". Formularz powinien wyglądać następująco:
Powiązanie danych
Następnym krokiem jest połączenie typów Product i Category z modelu z kontrolkami DataGridView . Spowoduje to powiązanie danych załadowanych przez program EF Core z kontrolkami, tak aby jednostki śledzone przez program EF Core były synchronizowane z tymi wyświetlanymi w kontrolkach.
Kliknij Glyph akcji Projektanta na pierwszym
DataGridView. Jest to mały przycisk w prawym górnym rogu kontrolki.
Spowoduje to otwarcie listy akcji, z której można uzyskać dostęp do listy rozwijanej Wybierz źródło danych. Nie utworzyliśmy jeszcze źródła danych, więc przejdź do dołu i wybierz pozycję Dodaj nowe źródło danych obiektu....
Wybierz pozycję Kategoria , aby utworzyć źródło danych obiektu dla kategorii, a następnie kliknij przycisk OK.
Wskazówka
Jeśli w tym miejscu nie są wyświetlane żadne typy źródeł danych, upewnij się, że
Product.cs,Category.csiProductsContext.cszostały dodane do projektu i że rozwiązanie zostało skompilowane.Teraz lista Wybierz źródło danych rozwijana zawiera właśnie utworzone źródło danych obiektu. Rozwiń Inne źródła danych, a następnie Źródła danych projektu i wybierz Kategorię.
Drugi
DataGridViewbędzie powiązany z produktami. Jednak zamiast wiązać się z typem najwyższego poziomuProduct, zostanie powiązany z nawigacjąProductswynikającą z powiązaniaCategorypierwszego elementuDataGridView. Oznacza to, że po wybraniu kategorii w pierwszym widoku produkty dla tej kategorii będą automatycznie używane w drugim widoku.Korzystając z Symbolu akcji projektanta na drugim
DataGridView, wybierz Wybierz źródło danych, a następnie rozwińcategoryBindingSourcei wybierzProducts.
Konfigurowanie wyświetlanych funkcji
Domyślnie w obiekcie DataGridView tworzona jest kolumna dla każdej właściwości typów powiązanych. Ponadto wartości dla każdej z tych właściwości można edytować przez użytkownika. Jednak niektóre wartości, takie jak wartości klucza podstawowego, są koncepcyjnie tylko do odczytu i nie powinny być edytowane. Ponadto niektóre właściwości, takie jak właściwość klucza obcego CategoryId i nawigacja Category , nie są przydatne dla użytkownika, a więc powinny być ukryte.
Wskazówka
Często ukrywa się właściwości klucza podstawowego w rzeczywistej aplikacji. Są one widoczne tutaj, aby ułatwić sprawdzenie, co program EF Core robi za kulisami.
Kliknij prawym przyciskiem myszy pierwszy
DataGridViewi wybierz polecenie Edytuj kolumny....
Ustaw kolumnę
CategoryId, która reprezentuje klucz podstawowy, tylko do odczytu, a następnie kliknij przycisk OK.
Kliknij prawym przyciskiem myszy drugą pozycję
DataGridViewi wybierz polecenie Edytuj kolumny.... Ustaw kolumnęProductIdjako tylko do odczytu, a następnie usuńCategoryIdkolumny iCategory, a następnie kliknij przycisk OK.
Nawiązywanie połączenia z platformą EF Core
Aplikacja potrzebuje teraz niewielkiej ilości kodu, aby połączyć program EF Core z kontrolkami powiązanymi z danymi.
MainFormOtwórz kod, klikając go prawym przyciskiem myszy i wybierając polecenie Wyświetl kod.
Dodaj pole prywatne do przechowywania
DbContextdla sesji oraz dodaj przesłonięcia dla metodOnLoadiOnClosing. Kod powinien wyglądać następująco:
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;
}
}
}
Metoda OnLoad jest wywoływana podczas ładowania formularza. W tej chwili
- Zostanie utworzone wystąpienie klasy
ProductsContext, które będzie używane do ładowania i śledzenia zmian w produktach i kategoriach wyświetlanych przez aplikację. -
EnsureCreatedjest wywoływane w elemencieDbContext, aby utworzyć bazę danych SQLite, jeśli jeszcze nie istnieje. Jest to szybki sposób tworzenia bazy danych podczas tworzenia prototypów lub testowania aplikacji. Jeśli jednak model ulegnie zmianie, należy usunąć bazę danych, aby można było ją utworzyć ponownie. (WierszEnsureDeletedmoże być odkomentowany, aby łatwo usunąć i ponownie utworzyć bazę danych przy uruchamianiu aplikacji). Zamiast tego możesz użyć EF Core Migrations do modyfikowania i aktualizowania schematu bazy danych bez utraty danych. -
EnsureCreatedspowoduje również wypełnienie nowej bazy danych danymi zdefiniowanymi w metodzieProductsContext.OnModelCreating. - Metoda rozszerzenia
Loadsłuży do ładowania wszystkich kategorii z bazy danych doDbContext. Te jednostki będą teraz śledzone przez elementDbContext, który wykryje wszelkie zmiany wprowadzone podczas edycji kategorii przez użytkownika. - Właściwość
categoryBindingSource.DataSourcejest inicjowana do kategorii, które są śledzone przez elementDbContext. Odbywa się to przez wywołanieLocal.ToBindingList()na właściwościCategoriesDbSet.Localzapewnia dostęp do lokalnego widoku śledzonych kategorii z zdarzeniami podłączonymi w celu zapewnienia, że dane lokalne pozostają zsynchronizowane z wyświetlanymi danymi i na odwrót.ToBindingList()uwidacznia te dane jako elementIBindingList, który jest rozumiany przez powiązanie danych formularzy systemu Windows.
Metoda OnClosing jest wywoływana, gdy formularz zostanie zamknięty. W tej chwili obiekt DbContext zostanie usunięty, co gwarantuje, że wszystkie zasoby bazy danych zostaną zwolnione, a dbContext pole zostanie ustawione na wartość null, aby nie można było go ponownie użyć.
Wypełnianie widoku produktami
Jeśli aplikacja została uruchomiona w tym momencie, powinna wyglądać mniej więcej tak:
Zwróć uwagę, że kategorie zostały załadowane z bazy danych, ale tabela products pozostaje pusta. Ponadto przycisk Zapisz nie działa.
Aby wypełnić tabelę products, program EF Core musi załadować produkty z bazy danych dla wybranej kategorii. Aby to osiągnąć:
W projektancie formularza głównego wybierz
DataGridViewdla kategorii.W obszarze Właściwości programu
DataGridView, wybierz zdarzenia (przycisk błyskawica), a następnie dwukrotnie kliknij zdarzenie SelectionChanged.
Spowoduje to utworzenie szablonu w kodzie formularza głównego dla zdarzenia, które ma zostać wyzwolone za każdym razem, gdy wybór kategorii ulegnie zmianie.
Wypełnij kod zdarzenia:
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();
}
}
}
W tym kodzie, jeśli istnieje aktywna (niepusta) DbContext sesja, to uzyskamy Category instancję powiązaną z aktualnie wybranym wierszem DataViewGrid. (Może to być null , jeśli wybrano ostatni wiersz w widoku, który jest używany do tworzenia nowych kategorii). Jeśli istnieje wybrana kategoria, DbContext zostanie ona poinstruowana o załadowaniu produktów skojarzonych z tą kategorią. Odbywa się to przez:
- Pobieranie elementu
EntityEntrydla wystąpieniaCategory(dbContext.Entry(category)) - Poinformowanie EF Core, że chcemy operować nawigacją kolekcji
ProductstegoCategory(.Collection(e => e.Products)) - Na koniec przekazujemy EF Core, że chcemy załadować tę kolekcję produktów z bazy danych (
.Load();)
Wskazówka
Po wywołaniu Load, EF Core uzyska dostęp do bazy danych tylko po to, aby załadować produkty, jeśli jeszcze nie zostały załadowane.
Jeśli aplikacja zostanie uruchomiona ponownie, należy załadować odpowiednie produkty za każdym razem, gdy wybrano kategorię:
Zapisywanie zmian
Na koniec przycisk Zapisz można połączyć z platformą EF Core, aby wszelkie zmiany wprowadzone w produktach i kategoriach zostały zapisane w bazie danych.
W projektancie formularza głównego wybierz przycisk Zapisz .
W obszarze Właściwości
Buttonwybierz zdarzenia (przycisk pioruna), a następnie dwukrotnie kliknij zdarzenie Click.
Wypełnij kod zdarzenia:
private void buttonSave_Click(object sender, EventArgs e)
{
this.dbContext!.SaveChanges();
this.dataGridViewCategories.Refresh();
this.dataGridViewProducts.Refresh();
}
Ten kod wywołuje SaveChanges na DbContext, co zapisuje wszelkie zmiany wprowadzone w bazie danych SQLite. Jeśli nie wprowadzono żadnych zmian, jest to operacja bez efektu i nie zostanie wykonane żadne wywołanie do bazy danych. Po zapisaniu kontrolki DataGridView zostaną odświeżone. Dzieje się tak, ponieważ program EF Core odczytuje wygenerowane wartości klucza podstawowego dla wszystkich nowych produktów i kategorii z bazy danych. Wywołanie Refresh aktualizuje ekran przy użyciu tych wygenerowanych wartości.
Ostateczna aplikacja
Oto pełny kod formularza głównego:
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();
}
}
}
Teraz można uruchomić aplikację, a produkty i kategorie można dodawać, usuwać i edytować. Zwróć uwagę, że jeśli przycisk Zapisz zostanie kliknięty przed zamknięciem aplikacji, wszystkie wprowadzone zmiany zostaną zapisane w bazie danych i ponownie załadowane po ponownym uruchomieniu aplikacji. Jeśli nie klikniesz przycisku Zapisz , wszelkie zmiany zostaną utracone po ponownym uruchomieniu aplikacji.
Wskazówka
Do pustego wiersza w dolnej części kontrolki można dodać nową kategorię DataViewControl lub produkt. Wiersz można usunąć, wybierając go i naciskając Del.
Przed zapisaniem
Po zapisaniu
Zwróć uwagę, że wartości klucza podstawowego dla dodanej kategorii i produktów są wypełniane po kliknięciu przycisku Zapisz .