WinForms ile Veri Bağlama
Bu adım adım izlenecek yol, POCO türlerinin "ana ayrıntı" biçimindeki Window Forms (WinForms) denetimlerine nasıl bağlanacağını gösterir. Uygulama, veritabanındaki verilerle nesneleri doldurmak, değişiklikleri izlemek ve verileri veritabanında kalıcı hale getirmek için Entity Framework kullanır.
Model, bire çok ilişkisine katılan iki tür tanımlar: Kategori (sorumlu\ana) ve Ürün (bağımlı\ayrıntı). Ardından, Modelde tanımlanan türleri WinForms denetimlerine bağlamak için Visual Studio araçları kullanılır. WinForms veri bağlama çerçevesi, ilgili nesneler arasında gezintiye olanak tanır: ana görünümde satırların seçilmesi, ayrıntı görünümünün ilgili alt verilerle güncelleştirilmesine neden olur.
Bu kılavuzdaki ekran görüntüleri ve kod listeleri Visual Studio 2013'ten alınmıştır, ancak bu kılavuzu Visual Studio 2012 veya Visual Studio 2010 ile tamamlayabilirsiniz.
Önkoşullar
Bu kılavuzu tamamlamak için Visual Studio 2013, Visual Studio 2012 veya Visual Studio 2010 yüklü olmalıdır.
Visual Studio 2010 kullanıyorsanız NuGet'i de yüklemeniz gerekir. Daha fazla bilgi için bkz . NuGet'i Yükleme.
Uygulamayı Oluşturma
- Visual Studio’yu açın
- Dosya -> Yeni -> Project....
- Sol bölmede Windows'a ve sağ bölmede Windows FormsUygulama'ya tıklayın
- Ad olarak WinFormswithEFSample girin
- Tamam'ı seçin
Entity Framework NuGet paketini yükleme
- Çözüm Gezgini'da WinFormswithEFSample projesine sağ tıklayın
- NuGet Paketlerini Yönet... öğesini seçin .
- NuGet Paketlerini Yönet iletişim kutusunda Çevrimiçi sekmesini seçin ve EntityFramework paketini seçin
- Yükle'ye tıklayın
Dekont
EntityFramework derlemesine ek olarak System.ComponentModel.DataAnnotations başvurusu da eklenir. Projenin System.Data.Entity başvurusu varsa, EntityFramework paketi yüklendiğinde kaldırılır. System.Data.Entity derlemesi artık Entity Framework 6 uygulamaları için kullanılmaz.
Koleksiyonlar için IListSource Uygulama
Koleksiyon özellikleri, Windows Forms kullanırken sıralama ile iki yönlü veri bağlamayı etkinleştirmek için IListSource arabirimini uygulamalıdır. Bunu yapmak için ObservableCollection'ı IListSource işlevselliğini ekleyecek şekilde genişleteceğiz.
- Projeye bir ObservableListSource sınıfı ekleyin:
- Proje adına sağ tıklayın
- Ekle -> Yeni Öğe'yi seçin
- Sınıf'ı seçin ve sınıf adı olarak ObservableListSource girin
- Varsayılan olarak oluşturulan kodu aşağıdaki kodla değiştirin:
Bu sınıf, sıralamanın yanı sıra iki yönlü veri bağlamayı da etkinleştirir. sınıfı ObservableCollection<T'den> türetilir ve IListSource'un açık bir uygulamasını ekler. IListSource'un GetList() yöntemi, ObservableCollection ile eşitlenmiş durumda kalan bir IBindingList uygulaması döndürmek için uygulanır. ToBindingList tarafından oluşturulan IBindingList uygulaması sıralamayı destekler. ToBindingList uzantısı yöntemi EntityFramework derlemesinde tanımlanır.
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Data.Entity;
namespace WinFormswithEFSample
{
public class ObservableListSource<T> : ObservableCollection<T>, IListSource
where T : class
{
private IBindingList _bindingList;
bool IListSource.ContainsListCollection { get { return false; } }
IList IListSource.GetList()
{
return _bindingList ?? (_bindingList = this.ToBindingList());
}
}
}
Model Tanımlama
Bu kılavuzda, Önce Kod veya EF Tasarım Aracı kullanarak bir model uygulamayı seçebilirsiniz. Aşağıdaki iki bölümden birini tamamlayın.
1. Seçenek: Önce Kod Kullanarak Model Tanımlama
Bu bölümde, Code First kullanarak modelin ve ilişkili veritabanının nasıl oluşturulacağı gösterilmektedir. EF tasarımcısını kullanarak modelinizi veritabanından tersine mühendislik uygulamak için Önce Veritabanı'nı kullanmayı tercih ediyorsanız sonraki bölüme (Seçenek 2: Önce Veritabanı kullanarak model tanımlama) atlayın
Code First geliştirmesini kullanırken genellikle kavramsal (etki alanı) modelinizi tanımlayan .NET Framework sınıfları yazarak başlarsınız.
- Projeye yeni bir Product sınıfı ekleme
- Varsayılan olarak oluşturulan kodu aşağıdaki kodla değiştirin:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinFormswithEFSample
{
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
}
- Projeye bir Kategori sınıfı ekleyin.
- Varsayılan olarak oluşturulan kodu aşağıdaki kodla değiştirin:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinFormswithEFSample
{
public class Category
{
private readonly ObservableListSource<Product> _products =
new ObservableListSource<Product>();
public int CategoryId { get; set; }
public string Name { get; set; }
public virtual ObservableListSource<Product> Products { get { return _products; } }
}
}
Varlıkları tanımlamaya ek olarak, DbContext'ten türetilen ve DbSet<TEntity> özelliklerini kullanıma sunan bir sınıf tanımlamanız gerekir. DbSet özellikleri, bağlama modele hangi türleri eklemek istediğinizi bildirir. DbContext ve DbSet türleri EntityFramework derlemesinde tanımlanır.
DbContext türetilmiş türünün bir örneği, çalışma zamanında varlık nesnelerini yönetir. Bu, nesneleri veritabanındaki verilerle doldurma, değişiklik izleme ve verileri veritabanında kalıcı hale getirme gibi işlemleri içerir.
- Projeye yeni bir ProductContext sınıfı ekleyin.
- Varsayılan olarak oluşturulan kodu aşağıdaki kodla değiştirin:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
namespace WinFormswithEFSample
{
public class ProductContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
}
Projeyi derleyin.
2. Seçenek: Önce Veritabanı kullanarak model tanımlama
Bu bölümde, EF tasarımcısını kullanarak modelinizi veritabanından tersine mühendislik uygulamak için Önce Veritabanı'nın nasıl kullanılacağı gösterilmektedir. Önceki bölümü tamamladıysanız (Seçenek 1: Önce Kod kullanarak model tanımlama), bu bölümü atlayın ve doğrudan Gecikmeli Yükleme bölümüne gidin.
Mevcut Veritabanı Oluşturma
Genellikle mevcut bir veritabanını hedeflediğiniz zaman zaten oluşturulur, ancak bu kılavuzda erişmek için bir veritabanı oluşturmamız gerekir.
Visual Studio ile yüklenen veritabanı sunucusu, yüklediğiniz Visual Studio sürümüne bağlı olarak farklıdır:
- Visual Studio 2010 kullanıyorsanız bir SQL Express veritabanı oluşturacaksınız.
- Visual Studio 2012 kullanıyorsanız bir LocalDB veritabanı oluşturacaksınız.
Şimdi veritabanını oluşturalım.
Görünüm -> Sunucu Gezgini
Veri Bağlan ions -> Bağlan Ekle... öğesine sağ tıklayın
Veri kaynağı olarak Microsoft SQL Server'ı seçmeniz gerekmeden önce Sunucu Gezgini'nden bir veritabanına bağlanmadıysanız
Hangisini yüklediğinize bağlı olarak LocalDB veya SQL Express'e Bağlan ve Veritabanı adı olarak ürünler
Tamam'ı seçtiğinizde yeni veritabanı oluşturmak isteyip istemediğiniz sorulur ve Evet'i seçin
Yeni veritabanı artık Sunucu Gezgini'nde görünür, sağ tıklayın ve Yeni Sorgu'yu seçin
Aşağıdaki SQL'i yeni sorguya kopyalayın, ardından sorguya sağ tıklayın ve Yürüt'e tıklayın
CREATE TABLE [dbo].[Categories] (
[CategoryId] [int] NOT NULL IDENTITY,
[Name] [nvarchar](max),
CONSTRAINT [PK_dbo.Categories] PRIMARY KEY ([CategoryId])
)
CREATE TABLE [dbo].[Products] (
[ProductId] [int] NOT NULL IDENTITY,
[Name] [nvarchar](max),
[CategoryId] [int] NOT NULL,
CONSTRAINT [PK_dbo.Products] PRIMARY KEY ([ProductId])
)
CREATE INDEX [IX_CategoryId] ON [dbo].[Products]([CategoryId])
ALTER TABLE [dbo].[Products] ADD CONSTRAINT [FK_dbo.Products_dbo.Categories_CategoryId] FOREIGN KEY ([CategoryId]) REFERENCES [dbo].[Categories] ([CategoryId]) ON DELETE CASCADE
Tersine Mühendislik Modeli
Modelimizi oluşturmak için Visual Studio'nun bir parçası olan Entity Framework Tasarım Aracı kullanacağız.
Proje -> Yeni Öğe Ekle...
Sol menüden Veri'yi seçin ve ardından Varlık Veri Modeli'ni ADO.NET
Ad olarak ProductModel yazın ve Tamam'a tıklayın
Bu işlem Varlık Veri Modeli Sihirbazı'nı başlatır
Veritabanından Oluştur'a tıklayın ve İleri'ye tıklayın
İlk bölümde oluşturduğunuz veritabanı bağlantısını seçin, bağlantı dizesi adı olarak ProductContext yazın ve İleri'ye tıklayın
'Tablolar' öğesinin yanındaki onay kutusuna tıklayarak tüm tabloları içeri aktarın ve 'Son'a tıklayın
Tersine mühendislik işlemi tamamlandıktan sonra yeni model projenize eklenir ve Entity Framework Tasarım Aracı'nde görüntülemeniz için açılır. Projenize veritabanı için bağlantı ayrıntılarıyla birlikte bir App.config dosyası da eklendi.
Visual Studio 2010'daki Ek Adımlar
Visual Studio 2010'da çalışıyorsanız EF tasarımcısını EF6 kod oluşturma özelliğini kullanacak şekilde güncelleştirmeniz gerekir.
- EF Tasarım Aracı modelinizin boş bir noktasına sağ tıklayın ve Kod Oluşturma Öğesi Ekle... öğesini seçin.
- Sol menüden Çevrimiçi Şablonlar'ı seçin ve DbContext araması yapın
- C# için EF 6.x DbContext Oluşturucusunu seçin, ad olarak ProductsModel yazın ve Ekle'ye tıklayın
Veri bağlama için kod oluşturma güncelleştiriliyor
EF, T4 şablonlarını kullanarak modelinizden kod oluşturur. Visual Studio ile gönderilen veya Visual Studio galerisinden indirilen şablonlar genel amaçlı kullanıma yöneliktir. Bu, bu şablonlardan oluşturulan varlıkların basit ICollection<T> özelliklerine sahip olduğu anlamına gelir. Ancak, veri bağlama yaparken IListSource uygulayan koleksiyon özelliklerine sahip olmak istenir. Bu nedenle yukarıda ObservableListSource sınıfını oluşturduk ve şimdi bu sınıfı kullanmak için şablonları değiştireceğiz.
Çözüm Gezgini açın ve ProductModel.edmx dosyasını bulun
ProductModel.edmx dosyasının altına yerleştirilecek ProductModel.tt dosyasını bulun
visual studio düzenleyicisinde açmak için ProductModel.tt dosyasına çift tıklayın
"ICollection" öğesinin iki örneğini bulun ve "ObservableListSource" ile değiştirin. Bunlar yaklaşık 296 ve 484 hatlarında bulunur.
"HashSet" öğesinin ilk oluşumunu bulun ve "ObservableListSource" ile değiştirin. Bu oluşum yaklaşık 50. satırda bulunur. Kodda daha sonra bulunan ikinci HashSet örneğini değiştirmeyin.
ProductModel.tt dosyasını kaydedin. Bu, varlıkların kodunun yeniden üretilmesine neden olmalıdır. Kod otomatik olarak yeniden oluşturulmazsa, ProductModel.tt sağ tıklayın ve "Özel Aracı Çalıştır"ı seçin.
Şimdi Category.cs dosyasını (ProductModel.tt altında iç içe yerleştirilmiştir) açarsanız, Products koleksiyonunun ObservableListSource<Product> türüne sahip olduğunu görmeniz gerekir.
Projeyi derleyin.
Geç Yükleme
Category sınıfındaki Products özelliği ve Product sınıfındaki Category özelliği gezinti özellikleridir. Entity Framework'te gezinti özellikleri, iki varlık türü arasındaki ilişkide gezinmek için bir yol sağlar.
EF, gezinti özelliğine ilk kez erişişiniz için veritabanından ilgili varlıkları otomatik olarak yükleme seçeneği sunar. Bu yükleme türüyle (gecikmeli yükleme olarak adlandırılır), her gezinti özelliğine ilk kez erişişinizde, içerik henüz bağlamda değilse veritabanında ayrı bir sorgu yürütüleceğini unutmayın.
POCO varlık türlerini kullanırken EF, çalışma zamanı sırasında türetilmiş proxy türlerinin örneklerini oluşturarak ve ardından yükleme kancasını eklemek için sınıflarınızdaki sanal özellikleri geçersiz kılarak yavaş yükleme sağlar. İlgili nesnelerin yavaş yüklenmesi için, gezinti özelliği alıcılarını genel ve sanal olarak bildirmeniz gerekir (Visual Basic'te Geçersiz Kılınabilir) ve sınıfınız korumalı olmamalıdır (Visual Basic'te NotOverridable). İlk Veritabanı gezinti özellikleri kullanılırken yavaş yüklemeyi etkinleştirmek için otomatik olarak sanal hale getirilir. İlk Kod bölümünde gezinti özelliklerini aynı nedenle sanal hale getirmeyi seçtik
Nesneyi Denetimlere Bağlama
Modelde tanımlanan sınıfları bu WinForms uygulaması için veri kaynakları olarak ekleyin.
Ana menüden Proje -> Yeni Veri Kaynağı Ekle ... öğesini seçin (Visual Studio 2010'da Veri -> Yeni Veri Kaynağı Ekle...) seçeneğini belirlemeniz gerekir
Veri Kaynağı Türü Seçin penceresinde Nesne'yi seçin ve İleri'ye tıklayın
Veri Nesnelerini Seç iletişim kutusunda WinFormswithEFSample dosyasını iki kez açın ve Kategori'yi seçin Ürün veri kaynağını seçmenize gerek yok, çünkü bu kaynağa Kategori veri kaynağındaki Ürün özelliği aracılığıyla ulaşacağız.
Son'a tıklayın. Veri Kaynakları penceresi görünmüyorsa Görünüm -> Diğer Windows-> Veri Kaynakları'nı seçin
Veri Kaynakları penceresinin otomatik olarak gizlenmemesi için raptiye simgesine basın. Pencere zaten görünür durumdaysa yenile düğmesine basmanız gerekebilir.
Çözüm Gezgini'da Form1.cs dosyasına çift tıklayarak ana formu tasarımcıda açın.
Kategori veri kaynağını seçin ve formda sürükleyin. Varsayılan olarak, tasarımcıya yeni bir DataGridView (categoryDataGridView) ve Gezinti araç çubuğu denetimleri eklenir. Bu denetimler, oluşturulan BindingSource (categoryBindingSource) ve Bağlama Gezgini (categoryBindingNavigator) bileşenlerine de bağlıdır.
CategoryDataGridView'da sütunları düzenleyin. CategoryId sütununu salt okunur olarak ayarlamak istiyoruz. CategoryId özelliğinin değeri, verileri kaydettikten sonra veritabanı tarafından oluşturulur.
- DataGridView denetimine sağ tıklayın ve Sütunları Düzenle... öğesini seçin.
- CategoryId sütununu seçin ve ReadOnly değerini True olarak ayarlayın
- Tamam'a basın
Kategori veri kaynağının altından Ürünler'i seçin ve formda sürükleyin. productDataGridView ve productBindingSource forma eklenir.
productDataGridView üzerindeki sütunları düzenleyin. CategoryId ve Category sütunlarını gizlemek ve ProductId değerini salt okunur olarak ayarlamak istiyoruz. ProductId özelliğinin değeri, verileri kaydettikten sonra veritabanı tarafından oluşturulur.
- DataGridView denetimine sağ tıklayın ve Sütunları Düzenle... öğesini seçin.
- ProductId sütununu seçin ve ReadOnly değerini True olarak ayarlayın.
- CategoryId sütununu seçin ve Kaldır düğmesine basın. Kategori sütunuyla da aynı işlemi yapın.
- Tamam'a basın.
Şimdiye kadar DataGridView denetimlerimizi tasarımcıdaki BindingSource bileşenleriyle ilişkilendirdik. Bir sonraki bölümde, categoryBindingSource.DataSource öğesini şu anda DbContext tarafından izlenen varlık koleksiyonuna ayarlamak için arkasındaki koda kod ekleyeceğiz. Kategori altındaki Ürünler'i sürüklediğimizde, WinForms productsBindingSource.DataSource özelliğini categoryBindingSource ve productsBindingSource.DataMember özelliğini Products olarak ayarlamayı üstlenmiş. Bu bağlama nedeniyle, productDataGridView içinde yalnızca seçili durumdaki Kategoriye ait ürünler görüntülenir.
Sağ fare düğmesine tıklayıp Etkin'i seçerek Gezinti araç çubuğundaKi Kaydet düğmesini etkinleştirin.
Kaydet düğmesine çift tıklayarak olay işleyicisini ekleyin. Bu işlem olay işleyicisini ekler ve sizi formun arkasındaki koda getirir. categoryBindingNavigatorSaveItem_Click olay işleyicisinin kodu sonraki bölümde eklenecektir.
Veri Etkileşimini İşleyen Kodu Ekleme
Şimdi veri erişimi gerçekleştirmek için ProductContext'i kullanacak kodu ekleyeceğiz. Ana form penceresinin kodunu aşağıda gösterildiği gibi güncelleştirin.
Kod, ProductContext'in uzun süre çalışan bir örneğini bildirir. ProductContext nesnesi, verileri sorgulamak ve veritabanına kaydetmek için kullanılır. ProductContext örneğindeki Dispose() yöntemi, geçersiz kılınan OnClosing yönteminden çağrılır. Kod açıklamaları, kodun ne yaptığı hakkında ayrıntılar sağlar.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.Entity;
namespace WinFormswithEFSample
{
public partial class Form1 : Form
{
ProductContext _context;
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_context = new ProductContext();
// Call the Load method to get the data for the given DbSet
// from the database.
// The data is materialized as entities. The entities are managed by
// the DbContext instance.
_context.Categories.Load();
// Bind the categoryBindingSource.DataSource to
// all the Unchanged, Modified and Added Category objects that
// are currently tracked by the DbContext.
// Note that we need to call ToBindingList() on the
// ObservableCollection<TEntity> returned by
// the DbSet.Local property to get the BindingList<T>
// in order to facilitate two-way binding in WinForms.
this.categoryBindingSource.DataSource =
_context.Categories.Local.ToBindingList();
}
private void categoryBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
// Currently, the Entity Framework doesn’t mark the entities
// that are removed from a navigation property (in our example the Products)
// as deleted in the context.
// The following code uses LINQ to Objects against the Local collection
// to find all products and marks any that do not have
// a Category reference as deleted.
// The ToList call is required because otherwise
// the collection will be modified
// by the Remove call while it is being enumerated.
// In most other situations you can do LINQ to Objects directly
// against the Local property without using ToList first.
foreach (var product in _context.Products.Local.ToList())
{
if (product.Category == null)
{
_context.Products.Remove(product);
}
}
// Save the changes to the database.
this._context.SaveChanges();
// Refresh the controls to show the values
// that were generated by the database.
this.categoryDataGridView.Refresh();
this.productsDataGridView.Refresh();
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
this._context.Dispose();
}
}
}
Windows Forms Uygulamasını Test Edin
Uygulamayı derleyip çalıştırın ve işlevselliği test edebilirsiniz.
Mağazayı kaydettikten sonra oluşturulan anahtarlar ekranda gösterilir.
Code First kullandıysanız, sizin için bir WinFormswithEFSample.ProductContext veritabanı oluşturulduğunu da görürsünüz.