Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Panduan langkah demi langkah ini menunjukkan cara membangun aplikasi Formulir Windows sederhana (WinForms) yang didukung oleh database SQLite. Aplikasi ini menggunakan Entity Framework Core (EF Core) untuk memuat data dari database, melacak perubahan yang dilakukan pada data tersebut, dan mempertahankan perubahan tersebut kembali ke database.
Cuplikan layar dan daftar kode dalam panduan ini diambil dari Visual Studio 2022 17.3.0.
Petunjuk / Saran
Anda dapat melihat contoh artikel ini di GitHub.
Prasyarat
Anda harus memasang Visual Studio 2022 versi 17.3 atau yang lebih baru dengan beban kerja .NET desktop yang dipilih untuk menyelesaikan panduan ini. Untuk informasi selengkapnya tentang menginstal Visual Studio versi terbaru, lihat Menginstal Visual Studio.
Membuat Aplikasi
Membuka Visual Studio
Di jendela mulai, pilih Buat proyek baru.
Pilih aplikasi Formulir Windows lalu pilih Berikutnya.
Di layar berikutnya, beri nama proyek, misalnya, GetStartedWinForms, dan pilih Berikutnya.
Di layar berikutnya, pilih versi .NET yang akan digunakan. Panduan ini dibuat dengan .NET 7, tetapi juga harus berfungsi dengan versi yang lebih baru.
Pilih Buat.
Menginstal paket EF Core NuGet
Klik kanan pada solusi dan pilih Kelola Paket NuGet untuk Solusi...
Pilih tab Telusuri dan cari "Microsoft.EntityFrameworkCore.Sqlite".
Pilih paket Microsoft.EntityFrameworkCore.Sqlite .
Periksa proyek GetStartedWinForms di panel kanan.
Pilih versi terbaru. Untuk menggunakan versi pra-rilis, pastikan kotak Sertakan prarilis dicentang.
Klik Instal
Catatan
Microsoft.EntityFrameworkCore.Sqlite adalah paket "penyedia database" untuk menggunakan EF Core dengan database SQLite. Paket serupa tersedia untuk sistem database lainnya. Menginstal paket penyedia database secara otomatis membawa semua dependensi yang diperlukan untuk menggunakan EF Core dengan sistem database tersebut. Ini termasuk paket dasar Microsoft.EntityFrameworkCore .
Tentukan Model
Dalam panduan ini kita akan menerapkan model menggunakan "Kode Pertama". Ini berarti bahwa EF Core akan membuat tabel database dan skema berdasarkan kelas C# yang Anda tentukan. Lihat Mengelola Skema Database untuk melihat cara menggunakan database yang sudah ada sebagai gantinya.
Klik kanan pada proyek dan pilih Tambahkan, lalu Kelas... untuk menambahkan kelas baru.
Gunakan nama
Product.csfile dan ganti kode untuk kelas dengan: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!; }Ulangi untuk membuat
Category.csdengan kode berikut: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(); }
Properti Products pada Category kelas dan properti Category pada Product kelas disebut "navigasi". Di EF Core, navigasi menentukan hubungan antara dua jenis entitas. Dalam hal ini, Product.Category navigasi mereferensikan kategori tempat produk tertentu berada. Demikian juga, navigasi koleksi Category.Products berisi semua produk untuk kategori tertentu.
Petunjuk / Saran
Saat menggunakan Windows Forms, ObservableCollectionListSource, yang mengimplementasikan IListSource, dapat digunakan untuk navigasi koleksi. Ini tidak diperlukan, tetapi meningkatkan pengalaman pengikatan data dua arah.
Tentukan DbContext
Di EF Core, kelas yang berasal dari DbContext digunakan untuk mengonfigurasi jenis entitas dalam model dan bertindak sebagai sesi untuk berinteraksi dengan database. Dalam kasus paling sederhana, kelas DbContext :
- Berisi
DbSetproperti untuk setiap jenis entitas dalam model. - Menimpa metode
OnConfiguringini untuk mengonfigurasi penyedia database dan string koneksi yang digunakan. Lihat Mengonfigurasi DbContext untuk informasi selengkapnya.
Dalam hal ini, kelas DbContext juga mengambil alih OnModelCreating metode untuk menyediakan beberapa data sampel untuk aplikasi.
Tambahkan kelas baru ProductsContext.cs ke proyek dengan kode berikut:
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" });
}
}
Pastikan untuk membangun solusi pada saat ini.
Menambahkan kontrol ke formulir
Aplikasi ini akan menampilkan daftar kategori dan daftar produk. Saat kategori dipilih dalam daftar pertama, maka daftar kedua akan berubah untuk menampilkan produk untuk kategori tersebut. Daftar ini dapat dimodifikasi untuk menambahkan, menghapus, atau mengedit produk dan kategori, dan perubahan ini dapat disimpan ke database SQLite dengan mengklik tombol Simpan .
Ubah nama formulir utama dari
Form1menjadiMainForm.
Dan ubah judul menjadi "Produk dan Kategori".
Menggunakan Toolbox, tambahkan dua
DataGridViewkontrol, disusun berdampingan.
Buka Properti untuk yang pertama
DataGridView, lalu ubah Nama menjadidataGridViewCategories.Di Properti untuk elemen kedua
DataGridView, ubah Nama menjadidataGridViewProducts.Dengan menggunakan Kotak Alat, tambahkan juga kontrol
Button.Beri nama tombol
buttonSavedan berikan teks "Simpan". Formulir akan terlihat seperti ini:
Pengikatan data
Langkah selanjutnya adalah menyambungkan tipe Product dan Category dari model ke kontrol DataGridView. Ini akan mengikat data yang dimuat oleh EF Core ke kontrol, sehingga entitas yang dilacak oleh EF Core tetap sinkron dengan yang ditampilkan dalam kontrol.
Klik Glyph Tindakan Perancang pada yang pertama
DataGridView. Ini adalah tombol kecil di sudut kanan atas kontrol.
Ini membuka Daftar Tindakan, dari mana drop-down untuk Memilih Sumber Data dapat diakses. Kami belum membuat sumber data, jadi buka bagian bawah dan pilih Tambahkan Sumber Data Objek baru....
Pilih Kategori untuk membuat sumber data objek untuk kategori, dan klik OK.
Petunjuk / Saran
Jika tidak ada jenis sumber data yang muncul di sini, pastikan bahwa
Product.cs,Category.cs, danProductsContext.cstelah ditambahkan ke proyek dan solusi telah dibangun.Sekarang drop-down Pilih Sumber Data berisi sumber data objek yang baru saja kita buat. Perluas Sumber Data Lain, lalu Sumber Data Proyek, dan pilih Kategori.
Elemen kedua
DataGridViewakan terikat pada produk. Namun, alih-alih terikat pada tipeProducttingkat atas, ini akan terikat pada navigasiProductsdari pengikatanCategoryyang pertamaDataGridView. Ini berarti bahwa ketika kategori dipilih dalam tampilan pertama, produk untuk kategori tersebut akan secara otomatis digunakan dalam tampilan kedua.Menggunakan Designer Action Glyph pada
DataGridViewkedua, pilih Pilih Sumber Data, lalu perluascategoryBindingSourcedan pilihProducts.
Mengonfigurasi apa yang ditampilkan
Secara default, kolom dibuat di DataGridView untuk setiap properti dari jenis terikat. Selain itu, nilai untuk setiap properti ini dapat diedit oleh pengguna. Namun, beberapa nilai, seperti nilai kunci utama, secara konseptual hanya dapat dibaca dan karena itu tidak boleh diedit. Selain itu, beberapa properti seperti properti kunci asing CategoryId dan navigasi Category tidak berguna bagi pengguna, sehingga harus disembunyikan.
Petunjuk / Saran
Adalah umum untuk menyembunyikan properti kunci utama dalam aplikasi nyata. Mereka dibiarkan terlihat di sini untuk memudahkan untuk melihat apa yang dilakukan EF Core di belakang layar.
Klik kanan pada kolom pertama
DataGridViewdan pilih Edit Kolom....
Jadikan kolom
CategoryId, yang mewakili kunci utama, sebagai hanya-baca, dan klik OK.
Klik kanan pada
DataGridViewkedua dan pilih Edit Kolom.... Jadikan kolomProductIdbaca-saja, dan hapus kolomCategoryIddanCategory, lalu klik OK.
Menghubungkan ke EF Core
Aplikasi sekarang membutuhkan sejumlah kecil kode untuk menghubungkan EF Core ke kontrol terikat data.
MainFormBuka kode dengan mengklik kanan pada file dan memilih Tampilkan Kode.
Tambahkan field pribadi untuk menyimpan
DbContextuntuk sesi, dan tambahkan penggantian untuk metodeOnLoaddanOnClosing. Kode akan terlihat seperti ini:
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;
}
}
}
Metode OnLoad ini dipanggil ketika formulir dimuat. Saat ini
- Instans
ProductsContextdibuat yang akan digunakan untuk memuat dan melacak perubahan pada produk dan kategori yang ditampilkan oleh aplikasi. -
EnsureCreateddipanggil padaDbContextuntuk membuat database SQLite jika belum tersedia. Ini adalah cara cepat untuk membuat database saat membuat prototipe atau menguji aplikasi. Namun, jika model berubah, maka database perlu dihapus sehingga dapat dibuat lagi.EnsureDeleted(Baris dapat tidak dikomentari untuk menghapus dan membuat ulang database dengan mudah saat aplikasi dijalankan.) Anda mungkin ingin menggunakan Migrasi Inti EF untuk memodifikasi dan memperbarui skema database tanpa kehilangan data apa pun. -
EnsureCreatedjuga akan mengisi database baru dengan data yang ditentukan dalamProductsContext.OnModelCreatingmetode . - Metode ekstensi
Loaddigunakan untuk mengambil semua kategori dari database keDbContextdalam. Entitas ini sekarang akan dilacak olehDbContext, yang akan mendeteksi perubahan apa pun yang dibuat ketika kategori diedit oleh pengguna. - Properti
categoryBindingSource.DataSourcediinisialisasi untuk kategori yang dilacak olehDbContext. Ini dilakukan dengan memanggilLocal.ToBindingList()pada propertiCategoriesDbSet.Localmenyediakan akses ke tampilan lokal kategori yang dilacak, dengan peristiwa yang dikaitkan untuk memastikan data lokal tetap sinkron dengan data yang ditampilkan, dan sebaliknya.ToBindingList()mengekspos data ini sebagaiIBindingList, yang dipahami oleh pengikatan data Formulir Windows.
Metode OnClosing ini dipanggil ketika formulir ditutup. Pada saat ini, DbContext dibuang, yang memastikan sumber daya basis data apa pun akan dilepaskan, dan kolom dbContext diatur ke null sehingga tidak dapat digunakan lagi.
Mengisi tampilan Produk
Jika aplikasi dimulai pada saat ini, maka aplikasi akan terlihat seperti ini:
Perhatikan bahwa kategori telah dimuat dari database, tetapi tabel produk tetap kosong. Selain itu, tombol Simpan tidak berfungsi.
Untuk mengisi tabel produk, EF Core perlu memuat produk dari database untuk kategori yang dipilih. Untuk mencapai ini:
Pada desainer untuk formulir utama, pilih
DataGridViewuntuk kategori.Pada Properti untuk
DataGridView, pilih kejadian (tombol kilat), dan klik dua kali pada kejadian SelectionChanged.
Ini akan membuat stub dalam kode formulir utama untuk peristiwa yang akan diaktifkan setiap kali pemilihan kategori berubah.
Isi kode untuk peristiwa:
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();
}
}
}
Dalam kode ini, jika ada sesi aktif (non-null) DbContext, kita mendapatkan Category instans yang terikat ke baris yang saat ini dipilih dari DataViewGrid. (Ini mungkin null jika baris akhir dalam tampilan dipilih, yang digunakan untuk membuat kategori baru.) Jika ada kategori yang dipilih, maka DbContext diinstruksikan untuk memuat produk yang terkait dengan kategori tersebut. Hal ini dilakukan dengan:
-
EntityEntryMendapatkan sebuahCategoryinstans (dbContext.Entry(category)) - Memberi tahu EF Core bahwa kami ingin beroperasi pada navigasi pengumpulan
ProductsdariCategory(.Collection(e => e.Products)) - Dan akhirnya memberi tahu EF Core bahwa kami ingin memuat koleksi produk tersebut dari database (
.Load();)
Petunjuk / Saran
Ketika Load dipanggil, EF Core hanya akan mengakses database untuk memuatkan produk jika produk tersebut belum dimuat.
Jika aplikasi sekarang dijalankan lagi, maka aplikasi harus memuat produk yang sesuai setiap kali kategori dipilih:
Menyimpan perubahan
Terakhir, tombol Simpan dapat disambungkan ke EF Core sehingga setiap perubahan yang dilakukan pada produk dan kategori disimpan ke database.
Di perancang untuk formulir utama, pilih tombol Simpan .
Di Properti untuk
Button, pilih event (tombol kilat), dan klik dua kali pada event Click.
Isi kode untuk peristiwa:
private void buttonSave_Click(object sender, EventArgs e)
{
this.dbContext!.SaveChanges();
this.dataGridViewCategories.Refresh();
this.dataGridViewProducts.Refresh();
}
Kode ini memanggil SaveChanges pada DbContext, yang menyimpan perubahan apa pun yang dilakukan pada database SQLite. Jika tidak ada perubahan yang dilakukan, maka ini adalah no-op, dan tidak ada panggilan database yang dilakukan. Setelah penyimpanan, kontrol DataGridView akan diperbarui. Ini karena EF Core membaca nilai kunci utama yang dihasilkan untuk produk dan kategori baru apa pun dari database. Memanggil Refresh akan memperbarui tampilan dengan nilai yang dihasilkan ini.
Aplikasi akhir
Berikut adalah kode lengkap untuk formulir utama:
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();
}
}
}
Aplikasi sekarang dapat dijalankan, dan produk dan kategori dapat ditambahkan, dihapus, dan diedit. Perhatikan bahwa jika tombol Simpan diklik sebelum menutup aplikasi, maka setiap perubahan yang dilakukan akan disimpan dalam database dan dimuat ulang saat aplikasi dimulai kembali. Jika Simpan tidak diklik, perubahan apa pun akan hilang saat aplikasi dimulai kembali.
Petunjuk / Saran
Kategori atau produk baru dapat ditambahkan ke DataViewControl menggunakan baris kosong di bagian bawah kontrol. Baris dapat dihapus dengan memilihnya dan menekan tombol Del .
Sebelum menyimpan
Setelah menyimpan
Perhatikan bahwa nilai kunci utama untuk kategori dan produk yang ditambahkan diisi saat Simpan diklik.