Kendi Kendine İzleme Varlıkları İzlenecek Yol

Önemli

Kendini izleyen varlıklar şablonunu kullanmanızı artık önermiyoruz. Yalnızca mevcut uygulamaları desteklemek için sunulmaya devam edecektir. Uygulamanız bağlantısız varlık graflarıyla çalışmayı gerektiriyorsa, topluluk tarafından daha etkin bir şekilde geliştirilen Kendini İzleyen Varlıklara benzer bir teknoloji olan İzlenebilir Varlıklar veya düşük düzeyli değişiklik izleme API’lerini kullanarak özel kod yazma gibi diğer alternatifleri göz önünde bulundurun.

Bu kılavuzda, bir Windows Communication Foundation (WCF) hizmetinin varlık grafı döndüren bir işlemi kullanıma sunma senaryosu gösterilmektedir. Ardından, bir istemci uygulaması bu grafiği işleyip değişiklikleri Entity Framework kullanarak güncelleştirmeleri doğrulayan ve veritabanına kaydeden bir hizmet işlemine gönderir.

Bu kılavuzu tamamlamadan önce Kendi Kendine İzleme Varlıkları sayfasını okuduğunuzdan emin olun.

Bu izlenecek yol aşağıdaki eylemleri tamamlar:

  • Erişecek bir veritabanı oluşturur.
  • Modeli içeren bir sınıf kitaplığı oluşturur.
  • Kendi Kendine İzleme Varlık Oluşturucu şablonuna geçiş yapılır.
  • Varlık sınıflarını ayrı bir projeye taşır.
  • Varlıkları sorgulamak ve kaydetmek için işlemleri kullanıma sunan bir WCF hizmeti oluşturur.
  • Hizmeti kullanan istemci uygulamaları (Konsol ve WPF) oluşturur.

Bu kılavuzda Önce Veritabanı kullanacağız ancak aynı teknikler Model First için de aynı şekilde geçerlidir.

Önkoşullar

Bu kılavuzu tamamlamak için Visual Studio'nun son sürümünü kullanmanız gerekir.

Veritabanı Oluşturma

Visual Studio ile yüklenen veritabanı sunucusu, yüklediğiniz Visual Studio sürümüne bağlı olarak farklıdır:

  • Visual Studio 2012 kullanıyorsanız bir LocalDB veritabanı oluşturacaksınız.
  • Visual Studio 2010 kullanıyorsanız bir SQL Express veritabanı oluşturacaksınız.

Şimdi veritabanını oluşturalım.

  • Visual Studio’yu açın
  • 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
  • Veritabanı adı olarak STESample girin
  • 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
  • Visual Studio 2012 kullanıyorsanız
    • Sunucu Gezgini'nde veritabanına 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
  • Visual Studio 2010 kullanıyorsanız
    • Veri -> İşlem SQL Düzenleyicisi -> Yeni Sorgu Bağlan... öğesini seçin.
    • Sunucu adı olarak .\SQLEXPRESS yazın ve Tamam'a tıklayın
    • Sorgu düzenleyicisinin üst kısmındaki açılan listeden STESample veritabanını seçin
    • Aşağıdaki SQL'i yeni sorguya kopyalayın, ardından sorguya sağ tıklayın ve SQL Yürüt'e tıklayın
    CREATE TABLE [dbo].[Blogs] (
        [BlogId] INT IDENTITY (1, 1) NOT NULL,
        [Name] NVARCHAR (200) NULL,
        [Url]  NVARCHAR (200) NULL,
        CONSTRAINT [PK_dbo.Blogs] PRIMARY KEY CLUSTERED ([BlogId] ASC)
    );

    CREATE TABLE [dbo].[Posts] (
        [PostId] INT IDENTITY (1, 1) NOT NULL,
        [Title] NVARCHAR (200) NULL,
        [Content] NTEXT NULL,
        [BlogId] INT NOT NULL,
        CONSTRAINT [PK_dbo.Posts] PRIMARY KEY CLUSTERED ([PostId] ASC),
        CONSTRAINT [FK_dbo.Posts_dbo.Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [dbo].[Blogs] ([BlogId]) ON DELETE CASCADE
    );

    SET IDENTITY_INSERT [dbo].[Blogs] ON
    INSERT INTO [dbo].[Blogs] ([BlogId], [Name], [Url]) VALUES (1, N'ADO.NET Blog', N'blogs.msdn.com/adonet')
    SET IDENTITY_INSERT [dbo].[Blogs] OFF
    INSERT INTO [dbo].[Posts] ([Title], [Content], [BlogId]) VALUES (N'Intro to EF', N'Interesting stuff...', 1)
    INSERT INTO [dbo].[Posts] ([Title], [Content], [BlogId]) VALUES (N'What is New', N'More interesting stuff...', 1)

Modeli Oluşturma

İlk olarak, modeli yerleştirmek için bir projeye ihtiyacımız var.

  • Dosya -> Yeni -> Proje...
  • Sol bölmeden Visual C# öğesini ve ardından Sınıf Kitaplığı'nı seçin
  • Ad olarak STESample girin ve Tamam'a tıklayın

Şimdi EF Tasarım Aracı veritabanımıza erişmek için basit bir model oluşturacağız:

  • Proje -> Yeni Öğe Ekle...
  • Sol bölmeden Veri'yi seçin ve varlık veri modelini ADO.NET
  • Ad olarak BloggingModel yazın ve Tamam'a tıklayın
  • Veritabanından oluştur'a tıklayın ve İleri'ye tıklayın
  • Önceki bölümde oluşturduğunuz veritabanının bağlantı bilgilerini girin
  • bağlantı dizesi adı olarak BloggingContext yazın ve İleri'ye tıklayın
  • Tablolar'ın yanındaki kutuyu işaretleyin ve Son'a tıklayın

STE Kodu Oluşturma ile Değiştirme

Şimdi varsayılan kod oluşturmayı devre dışı bırakmamız ve Kendi kendine İzleme Varlıklarına değiştirmemiz gerekiyor.

Visual Studio 2012 kullanıyorsanız

  • Çözüm Gezgini'de BloggingModel.edmx'i genişletin ve BloggingModel.tt silin ve BloggingModel.Context.ttBu, varsayılan kod oluşturmayı devre dışı bırakır
  • EF Tasarım Aracı yüzeyinde boş bir alana sağ tıklayın ve Kod Oluşturma Öğesi Ekle... öğesini seçin.
  • Sol bölmeden Çevrimiçi'yi seçin ve STE Oluşturucu için arama yapın
  • C# için STE Oluşturucu şablonunu seçin, ad olarak STETemplate yazın ve Ekle'ye tıklayın
  • STETemplate.tt ve STETemplate.Context.tt dosyaları BloggingModel.edmx dosyasının altına eklenir

Visual Studio 2010 kullanıyorsanız

  • EF Tasarım Aracı yüzeyinde boş bir alana sağ tıklayın ve Kod Oluşturma Öğesi Ekle... öğesini seçin.
  • Sol bölmeden Kod'a tıklayın ve ardından Kendi Kendine İzleme Varlık Oluşturucu'ADO.NET
  • Ad olarak STETemplate yazın ve Ekle'ye tıklayın
  • STETemplate.tt ve STETemplate.Context.tt dosyaları doğrudan projenize eklenir

Varlık Türlerini Ayrı Projeye Taşıma

Kendi Kendine İzleme Varlıklarını kullanmak için istemci uygulamamızın modelimizden oluşturulan varlık sınıflarına erişmesi gerekir. Modelin tamamını istemci uygulamasına göstermek istemediğimiz için varlık sınıflarını ayrı bir projeye taşıyacağız.

İlk adım, var olan projede varlık sınıfları oluşturma işlemini durdurmaktır:

  • Çözüm Gezgini STETemplate.tt sağ tıklayın ve Özellikler'i seçin
  • Özellikler penceresinde CustomTool özelliğinden TextTemplatingFileGenerator öğesini temizleyin
  • Çözüm Gezgini'da STETemplate.tt genişletin ve altında iç içe yerleştirilmiş tüm dosyaları silin

Şimdi yeni bir proje ekleyecek ve içindeki varlık sınıflarını oluşturacağız

  • Dosya -> Ekle -> Proje...

  • Sol bölmeden Visual C# öğesini ve ardından Sınıf Kitaplığı'nı seçin

  • Ad olarak STESample.Entities yazın ve Tamam'a tıklayın

  • Proje -> Varolan ÖğeYi Ekle...

  • STESample proje klasörüne gidin

  • Tüm Dosyaları görüntülemek için seçin (*.*)

  • STETemplate.tt dosyasını seçin

  • Ekle düğmesinin yanındaki açılan oka tıklayın ve Bağlantı Olarak Ekle'yi seçin

    Add Linked Template

Ayrıca varlık sınıflarının bağlamla aynı ad alanında oluşturulduğundan da emin olacağız. Bu, uygulamamız genelinde eklememiz gereken using deyimlerinin sayısını azaltır.

  • Çözüm Gezgini bağlı STETemplate.tt sağ tıklayın ve Özellikler'i seçin
  • Özellikler penceresinde Özel Araç Ad Alanı'nı STESample olarak ayarlayın

STE şablonu tarafından oluşturulan kodun derlenmesi için System.Runtime.Serialization başvurusu gerekir. Bu kitaplık, serileştirilebilir varlık türlerinde kullanılan WCF DataContract ve DataMember öznitelikleri için gereklidir.

  • Çözüm Gezgini'da STESample.Entities projesine sağ tıklayın ve Başvuru Ekle... öğesini seçin.
    • Visual Studio 2012'de - System.Runtime.Serialization'ın yanındaki kutuyu işaretleyin ve Tamam'a tıklayın
    • Visual Studio 2010'da System.Runtime.Serialization'ı seçin ve Tamam'a tıklayın

Son olarak, içinde bağlamımız bulunan projenin varlık türlerine bir başvurusu olması gerekir.

  • Çözüm Gezgini'da STESample projesine sağ tıklayın ve Başvuru Ekle... seçeneğini belirleyin.
    • Visual Studio 2012'de sol bölmeden Çözüm'e tıklayın, STESample.Entities'ın yanındaki kutuyu işaretleyin ve Tamam'a tıklayın
    • Visual Studio 2010'da Projeler sekmesini seçin, STESample.Entities öğesini seçin ve Tamam'a tıklayın

Dekont

Varlık türlerini ayrı bir projeye taşımak için bir diğer seçenek de şablon dosyasını varsayılan konumundan bağlamak yerine taşımaktır. Bunu yaparsanız, edmx dosyasının göreli yolunu sağlamak için şablondaki inputFile değişkenini güncelleştirmeniz gerekir (bu örnekte .. \BloggingModel.edmx).

WCF Hizmeti Oluşturma

Şimdi verilerimizi kullanıma sunma amacıyla bir WCF Hizmeti ekleme zamanı geldi, projeyi oluşturarak başlayacağız.

  • Dosya -> Ekle -> Proje...
  • Sol bölmeden Visual C# öğesini ve ardından WCF Hizmet Uygulaması'nı seçin
  • Ad olarak STESample.Service girin ve Tamam'a tıklayın
  • System.Data.Entity derlemesine başvuru ekleme
  • STESample ve STESample.Entities projelerine başvuru ekleme

Çalışma zamanında bulunması için EF bağlantı dizesi bu projeye kopyalamamız gerekir.

  • **STESample **projesi için App.Config dosyasını açın ve connectionStrings öğesini kopyalayın
  • connectionStrings öğesini STESample.Service projesinde Web.Config dosyasının yapılandırma öğesinin alt öğesi olarak yapıştırın

Şimdi gerçek hizmeti uygulama zamanı.

  • IService1.cs dosyasını açın ve içeriğini aşağıdaki kodla değiştirin
    using System.Collections.Generic;
    using System.ServiceModel;

    namespace STESample.Service
    {
        [ServiceContract]
        public interface IService1
        {
            [OperationContract]
            List<Blog> GetBlogs();

            [OperationContract]
            void UpdateBlog(Blog blog);
        }
    }
  • Service1.svc dosyasını açın ve içeriğini aşağıdaki kodla değiştirin
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;

    namespace STESample.Service
    {
        public class Service1 : IService1
        {
            /// <summary>
            /// Gets all the Blogs and related Posts.
            /// </summary>
            public List<Blog> GetBlogs()
            {
                using (BloggingContext context = new BloggingContext())
                {
                    return context.Blogs.Include("Posts").ToList();
                }
            }

            /// <summary>
            /// Updates Blog and its related Posts.
            /// </summary>
            public void UpdateBlog(Blog blog)
            {
                using (BloggingContext context = new BloggingContext())
                {
                    try
                    {
                        // TODO: Perform validation on the updated order before applying the changes.

                        // The ApplyChanges method examines the change tracking information
                        // contained in the graph of self-tracking entities to infer the set of operations
                        // that need to be performed to reflect the changes in the database.
                        context.Blogs.ApplyChanges(blog);
                        context.SaveChanges();

                    }
                    catch (UpdateException)
                    {
                        // To avoid propagating exception messages that contain sensitive data to the client tier
                        // calls to ApplyChanges and SaveChanges should be wrapped in exception handling code.
                        throw new InvalidOperationException("Failed to update. Try your request again.");
                    }
                }
            }        
        }
    }

Hizmeti Konsol Uygulamasından Kullanma

Şimdi hizmetimizi kullanan bir konsol uygulaması oluşturalım.

  • Dosya -> Yeni -> Proje...
  • Sol bölmeden Visual C# öğesini ve ardından Konsol Uygulaması'nı seçin
  • Ad olarak STESample.ConsoleTest yazın ve Tamam'a tıklayın
  • STESample.Entities projesine başvuru ekleme

WCF hizmetimiz için bir hizmet başvurusuna ihtiyacımız var

  • Çözüm Gezgini'da STESample.ConsoleTest projesine sağ tıklayın ve Hizmet Başvurusu Ekle... öğesini seçin.
  • Bul'a tıklayın
  • Ad alanı olarak BloggingService girin ve Tamam'a tıklayın

Artık hizmeti kullanmak için bazı kodlar yazabiliriz.

  • Program.cs dosyasını açın ve içeriğini aşağıdaki kodla değiştirin.
    using STESample.ConsoleTest.BloggingService;
    using System;
    using System.Linq;

    namespace STESample.ConsoleTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                // Print out the data before we change anything
                Console.WriteLine("Initial Data:");
                DisplayBlogsAndPosts();

                // Add a new Blog and some Posts
                AddBlogAndPost();
                Console.WriteLine("After Adding:");
                DisplayBlogsAndPosts();

                // Modify the Blog and one of its Posts
                UpdateBlogAndPost();
                Console.WriteLine("After Update:");
                DisplayBlogsAndPosts();

                // Delete the Blog and its Posts
                DeleteBlogAndPost();
                Console.WriteLine("After Delete:");
                DisplayBlogsAndPosts();

                Console.WriteLine("Press any key to exit...");
                Console.ReadKey();
            }

            static void DisplayBlogsAndPosts()
            {
                using (var service = new Service1Client())
                {
                    // Get all Blogs (and Posts) from the service
                    // and print them to the console
                    var blogs = service.GetBlogs();
                    foreach (var blog in blogs)
                    {
                        Console.WriteLine(blog.Name);
                        foreach (var post in blog.Posts)
                        {
                            Console.WriteLine(" - {0}", post.Title);
                        }
                    }
                }

                Console.WriteLine();
                Console.WriteLine();
            }

            static void AddBlogAndPost()
            {
                using (var service = new Service1Client())
                {
                    // Create a new Blog with a couple of Posts
                    var newBlog = new Blog
                    {
                        Name = "The New Blog",
                        Posts =
                        {
                            new Post { Title = "Welcome to the new blog"},
                            new Post { Title = "What's new on the new blog"}
                        }
                    };

                    // Save the changes using the service
                    service.UpdateBlog(newBlog);
                }
            }

            static void UpdateBlogAndPost()
            {
                using (var service = new Service1Client())
                {
                    // Get all the Blogs
                    var blogs = service.GetBlogs();

                    // Use LINQ to Objects to find The New Blog
                    var blog = blogs.First(b => b.Name == "The New Blog");

                    // Update the Blogs name
                    blog.Name = "The Not-So-New Blog";

                    // Update one of the related posts
                    blog.Posts.First().Content = "Some interesting content...";

                    // Save the changes using the service
                    service.UpdateBlog(blog);
                }
            }

            static void DeleteBlogAndPost()
            {
                using (var service = new Service1Client())
                {
                    // Get all the Blogs
                    var blogs = service.GetBlogs();

                    // Use LINQ to Objects to find The Not-So-New Blog
                    var blog = blogs.First(b => b.Name == "The Not-So-New Blog");

                    // Mark all related Posts for deletion
                    // We need to call ToList because each Post will be removed from the
                    // Posts collection when we call MarkAsDeleted
                    foreach (var post in blog.Posts.ToList())
                    {
                        post.MarkAsDeleted();
                    }

                    // Mark the Blog for deletion
                    blog.MarkAsDeleted();

                    // Save the changes using the service
                    service.UpdateBlog(blog);
                }
            }
        }
    }

Artık uygulamayı çalıştırarak çalışır durumda görebilirsiniz.

  • Çözüm Gezgini'da STESample.ConsoleTest projesine sağ tıklayın ve Hata Ayıkla -> Yeni örneği başlat'ı seçin

Uygulama yürütürken aşağıdaki çıkışı görürsünüz.

Initial Data:
ADO.NET Blog
- Intro to EF
- What is New

After Adding:
ADO.NET Blog
- Intro to EF
- What is New
The New Blog
- Welcome to the new blog
- What's new on the new blog

After Update:
ADO.NET Blog
- Intro to EF
- What is New
The Not-So-New Blog
- Welcome to the new blog
- What's new on the new blog

After Delete:
ADO.NET Blog
- Intro to EF
- What is New

Press any key to exit...

Wpf Uygulamasından Hizmeti Kullanma

Şimdi hizmetimizi kullanan bir WPF uygulaması oluşturalım.

  • Dosya -> Yeni -> Proje...
  • Sol bölmeden Visual C# öğesini ve ardından WPF Uygulaması'nı seçin
  • Ad olarak STESample.WPFTest girin ve Tamam'a tıklayın
  • STESample.Entities projesine başvuru ekleme

WCF hizmetimiz için bir hizmet başvurusuna ihtiyacımız var

  • Çözüm Gezgini'da STESample.WPFTest projesine sağ tıklayın ve Hizmet Başvurusu Ekle... öğesini seçin.
  • Bul'a tıklayın
  • Ad alanı olarak BloggingService girin ve Tamam'a tıklayın

Artık hizmeti kullanmak için bazı kodlar yazabiliriz.

  • MainWindow.xaml dosyasını açın ve içeriğini aşağıdaki kodla değiştirin.
    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:STESample="clr-namespace:STESample;assembly=STESample.Entities"
        mc:Ignorable="d" x:Class="STESample.WPFTest.MainWindow"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">

        <Window.Resources>
            <CollectionViewSource
                x:Key="blogViewSource"
                d:DesignSource="{d:DesignInstance {x:Type STESample:Blog}, CreateList=True}"/>
            <CollectionViewSource
                x:Key="blogPostsViewSource"
                Source="{Binding Posts, Source={StaticResource blogViewSource}}"/>
        </Window.Resources>

        <Grid DataContext="{StaticResource blogViewSource}">
            <DataGrid AutoGenerateColumns="False" EnableRowVirtualization="True"
                      ItemsSource="{Binding}" Margin="10,10,10,179">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding BlogId}" Header="Id" Width="Auto" IsReadOnly="True" />
                    <DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="Auto"/>
                    <DataGridTextColumn Binding="{Binding Url}" Header="Url" Width="Auto"/>
                </DataGrid.Columns>
            </DataGrid>
            <DataGrid AutoGenerateColumns="False" EnableRowVirtualization="True"
                      ItemsSource="{Binding Source={StaticResource blogPostsViewSource}}" Margin="10,145,10,38">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding PostId}" Header="Id" Width="Auto"  IsReadOnly="True"/>
                    <DataGridTextColumn Binding="{Binding Title}" Header="Title" Width="Auto"/>
                    <DataGridTextColumn Binding="{Binding Content}" Header="Content" Width="Auto"/>
                </DataGrid.Columns>
            </DataGrid>
            <Button Width="68" Height="23" HorizontalAlignment="Right" VerticalAlignment="Bottom"
                    Margin="0,0,10,10" Click="buttonSave_Click">Save</Button>
        </Grid>
    </Window>
  • MainWindow (MainWindow.xaml.cs) için arkasındaki kodu açın ve içeriğini aşağıdaki kodla değiştirin
    using STESample.WPFTest.BloggingService;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;

    namespace STESample.WPFTest
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }

            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                using (var service = new Service1Client())
                {
                    // Find the view source for Blogs and populate it with all Blogs (and related Posts)
                    // from the Service. The default editing functionality of WPF will allow the objects
                    // to be manipulated on the screen.
                    var blogsViewSource = (CollectionViewSource)this.FindResource("blogViewSource");
                    blogsViewSource.Source = service.GetBlogs().ToList();
                }
            }

            private void buttonSave_Click(object sender, RoutedEventArgs e)
            {
                using (var service = new Service1Client())
                {
                    // Get the blogs that are bound to the screen
                    var blogsViewSource = (CollectionViewSource)this.FindResource("blogViewSource");
                    var blogs = (List<Blog>)blogsViewSource.Source;

                    // Save all Blogs and related Posts
                    foreach (var blog in blogs)
                    {
                        service.UpdateBlog(blog);
                    }

                    // Re-query for data to get database-generated keys etc.
                    blogsViewSource.Source = service.GetBlogs().ToList();
                }
            }
        }
    }

Artık uygulamayı çalıştırarak çalışır durumda görebilirsiniz.

  • Çözüm Gezgini'da STESample.WPFTest projesine sağ tıklayın ve Hata Ayıkla -> Yeni örnek başlat'ı seçin
  • Ekranı kullanarak verileri işleyebilir ve Kaydet düğmesini kullanarak hizmet aracılığıyla kaydedebilirsiniz

WPF Main window