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

    Change Data Source

  • Hangisini yüklediğinize bağlı olarak LocalDB veya SQL Express'e Bağlan ve Veritabanı adı olarak ürünler

    Add Connection LocalDB

    Add Connection Express

  • Tamam'ı seçtiğinizde yeni veritabanı oluşturmak isteyip istemediğiniz sorulur ve Evet'i seçin

    Create Database

  • 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

    Choose Model Contents

  • İ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

    Choose Your Connection

  • 'Tablolar' öğesinin yanındaki onay kutusuna tıklayarak tüm tabloları içeri aktarın ve 'Son'a tıklayın

    Choose Your Objects

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

    Product Model Template

  • 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.

    Data Source

  • 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.

    Data Source 2

  • Çö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.

    Form 1 Designer

  • 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.

    Form 1 Before Save

  • Mağazayı kaydettikten sonra oluşturulan anahtarlar ekranda gösterilir.

    Form 1 After Save

  • Code First kullandıysanız, sizin için bir WinFormswithEFSample.ProductContext veritabanı oluşturulduğunu da görürsünüz.

    Server Object Explorer