Bagikan melalui


Panduan Entitas Pelacakan Mandiri

Penting

Kami tidak lagi merekomendasikan penggunaan templat entitas pelacakan mandiri. Ini hanya akan terus tersedia untuk mendukung aplikasi yang ada. Jika aplikasi Anda mengharuskan bekerja dengan grafik entitas yang terputus, pertimbangkan alternatif lain seperti Entitas yang Dapat Dilacak, yang merupakan teknologi yang mirip dengan Entitas Pelacakan Mandiri yang lebih aktif dikembangkan oleh komunitas, atau menulis kode kustom menggunakan API pelacakan perubahan tingkat rendah.

Panduan ini menunjukkan skenario di mana layanan Windows Communication Foundation (WCF) mengekspos operasi yang mengembalikan grafik entitas. Selanjutnya, aplikasi klien memanipulasi grafik tersebut dan mengirimkan modifikasi ke operasi layanan yang memvalidasi dan menyimpan pembaruan ke database menggunakan Entity Framework.

Sebelum menyelesaikan panduan ini, pastikan Anda membaca halaman Entitas Pelacakan Mandiri.

Panduan ini menyelesaikan tindakan berikut:

  • Membuat database untuk diakses.
  • Membuat pustaka kelas yang berisi model.
  • Tukar ke templat Generator Entitas Pelacakan Mandiri.
  • Memindahkan kelas entitas ke proyek terpisah.
  • Membuat layanan WCF yang mengekspos operasi untuk mengkueri dan menyimpan entitas.
  • Membuat aplikasi klien (Konsol dan WPF) yang menggunakan layanan.

Kita akan menggunakan Database First dalam panduan ini tetapi teknik yang sama berlaku sama untuk Model First.

Prasyarat

Untuk menyelesaikan panduan ini, Anda memerlukan versi Terbaru Visual Studio.

Membuat database

Server database yang diinstal dengan Visual Studio berbeda tergantung pada versi Visual Studio yang telah Anda instal:

  • Jika Anda menggunakan Visual Studio 2012, Maka Anda akan membuat database LocalDB.
  • Jika Anda menggunakan Visual Studio 2010, Anda akan membuat database SQL Express.

Mari kita lanjutkan dan hasilkan database.

  • Membuka Visual Studio
  • Tampilan -> Penjelajah Server
  • Klik kanan pada Data Koneksi ions -> Tambahkan Koneksi ion...
  • Jika Anda belum tersambung ke database dari Server Explorer sebelum Anda harus memilih Microsoft SQL Server sebagai sumber data
  • Koneksi ke LocalDB atau SQL Express, tergantung pada yang telah Anda instal
  • Masukkan STESample sebagai nama database
  • Pilih OK dan Anda akan ditanya apakah Anda ingin membuat database baru, pilih Ya
  • Database baru sekarang akan muncul di Server Explorer
  • Jika Anda menggunakan Visual Studio 2012
    • Klik kanan pada database di Server Explorer dan pilih Kueri Baru
    • Salin SQL berikut ke dalam kueri baru, lalu klik kanan pada kueri dan pilih Jalankan
  • Jika Anda menggunakan Visual Studio 2010
    • Pilih Data -> Editor SQL Bertransaksi -> Koneksi kueri Baru...
    • Masukkan .\SQLEXPRESS sebagai nama server dan klik OK
    • Pilih database STESample dari menu drop-down di bagian atas editor kueri
    • Salin SQL berikut ke dalam kueri baru, lalu klik kanan pada kueri dan pilih Jalankan SQL
    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)

Membuat Model

Pertama- tama, kita perlu proyek untuk menempatkan model.

  • File -> Baru -> Proyek...
  • Pilih Visual C# dari panel kiri lalu Pustaka Kelas
  • Masukkan STESample sebagai nama dan klik OK

Sekarang kita akan membuat model sederhana di EF Designer untuk mengakses database kita:

  • Project -> Tambahkan Item Baru...
  • Pilih Data dari panel kiri lalu ADO.NET Model Data Entitas
  • Masukkan BloggingModel sebagai nama dan klik OK
  • Pilih Buat dari database dan klik Berikutnya
  • Masukkan informasi koneksi untuk database yang Anda buat di bagian sebelumnya
  • Masukkan BloggingContext sebagai nama untuk string koneksi dan klik Berikutnya
  • Centang kotak di samping Tabel dan klik Selesai

Tukar ke Pembuatan Kode STE

Sekarang kita perlu menonaktifkan pembuatan kode default dan bertukar ke Entitas Pelacakan Mandiri.

Jika Anda menggunakan Visual Studio 2012

  • Perluas BloggingModel.edmx di Penjelajah Solusi dan hapus BloggingModel.tt dan BloggingModel.Context.ttIni akan menonaktifkan pembuatan kode default
  • Klik kanan area kosong pada permukaan Desainer EF dan pilih Tambahkan Item Pembuatan Kode...
  • Pilih Online dari panel kiri dan cari STE Generator
  • Pilih templat STE Generator untuk C#, masukkan STETemplate sebagai nama dan klik Tambahkan
  • File STETemplate.tt dan STETemplate.Context.tt ditambahkan berlapis di bawah file BloggingModel.edmx

Jika Anda menggunakan Visual Studio 2010

  • Klik kanan area kosong pada permukaan Desainer EF dan pilih Tambahkan Item Pembuatan Kode...
  • Pilih Kode dari panel kiri lalu ADO.NET Generator Entitas Pelacakan Mandiri
  • Masukkan STETemplate sebagai nama dan klik Tambahkan
  • File STETemplate.tt dan STETemplate.Context.tt ditambahkan langsung ke proyek Anda

Pindahkan Jenis Entitas ke Proyek Terpisah

Untuk menggunakan Entitas Pelacakan Mandiri, aplikasi klien kami memerlukan akses ke kelas entitas yang dihasilkan dari model kami. Karena kami tidak ingin mengekspos seluruh model ke aplikasi klien, kami akan memindahkan kelas entitas ke dalam proyek terpisah.

Langkah pertama adalah berhenti menghasilkan kelas entitas dalam proyek yang ada:

  • Klik kanan pada STETemplate.tt di Penjelajah Solusi dan pilih Properti
  • Di jendela Properti bersihkan TextTemplatingFileGenerator dari properti CustomTool
  • Perluas STETemplate.tt di Penjelajah Solusi dan hapus semua file yang berlapis di bawahnya

Selanjutnya, kita akan menambahkan proyek baru dan menghasilkan kelas entitas di dalamnya

  • File -> Tambahkan -> Proyek...

  • Pilih Visual C# dari panel kiri lalu Pustaka Kelas

  • Masukkan STESample.Entities sebagai nama dan klik OK

  • Proyek -> Tambahkan Item yang Ada...

  • Menavigasi ke folder proyek STESample

  • Pilih untuk melihat Semua File (*.*)

  • Pilih file STETemplate.tt

  • Klik panah turun bawah di samping tombol Tambahkan dan pilih Tambahkan Sebagai Tautan

    Add Linked Template

Kita juga akan memastikan kelas entitas dihasilkan di namespace yang sama dengan konteks. Ini hanya mengurangi jumlah penggunaan pernyataan yang perlu kita tambahkan di seluruh aplikasi kita.

  • Klik kanan pada STETemplate.tt tertaut di Penjelajah Solusi dan pilih Properti
  • Di jendela Properti atur Namespace Layanan Alat Kustom ke STESample

Kode yang dihasilkan oleh templat STE akan memerlukan referensi ke System.Runtime.Serialization untuk mengkompilasi. Pustaka ini diperlukan untuk atribut WCF DataContract dan DataMember yang digunakan pada jenis entitas yang dapat diserialisasikan .

  • Klik kanan pada proyek STESample.Entities di Penjelajah Solusi dan pilih Tambahkan Referensi...
    • Di Visual Studio 2012 - centang kotak di samping System.Runtime.Serialization dan klik OK
    • Di Visual Studio 2010 - pilih System.Runtime.Serialization dan klik OK

Akhirnya, proyek dengan konteks kami di dalamnya akan membutuhkan referensi ke jenis entitas.

  • Klik kanan pada proyek STESample di Penjelajah Solusi dan pilih Tambahkan Referensi...
    • Di Visual Studio 2012 - pilih Solusi dari panel kiri, centang kotak di samping STESample.Entities dan klik OK
    • Di Visual Studio 2010 - pilih tab Proyek, pilih STESample.Entities dan klik OK

Catatan

Opsi lain untuk memindahkan jenis entitas ke proyek terpisah adalah memindahkan file templat, daripada menautkannya dari lokasi defaultnya. Jika Anda melakukan ini, Anda harus memperbarui variabel inputFile dalam templat untuk menyediakan jalur relatif ke file edmx (dalam contoh ini adalah .. \BloggingModel.edmx).

Membuat Layanan WCF

Sekarang saatnya untuk menambahkan Layanan WCF untuk mengekspos data kami, kita akan mulai dengan membuat proyek.

  • File -> Tambahkan -> Proyek...
  • Pilih Visual C# dari panel kiri lalu Aplikasi Layanan WCF
  • Masukkan STESample.Service sebagai nama dan klik OK
  • Menambahkan referensi ke rakitan System.Data.Entity
  • Menambahkan referensi ke proyek STESample dan STESample.Entities

Kita perlu menyalin string koneksi EF ke proyek ini sehingga ditemukan pada runtime.

  • Buka file App.Config untuk **STESample **project dan salin elemen connectionStrings
  • Tempelkan elemen connectionStrings sebagai elemen turunan dari elemen konfigurasi file Web.Config di proyek STESample.Service

Sekarang saatnya untuk menerapkan layanan aktual.

  • Buka IService1.cs dan ganti konten dengan kode berikut
    using System.Collections.Generic;
    using System.ServiceModel;

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

            [OperationContract]
            void UpdateBlog(Blog blog);
        }
    }
  • Buka Service1.svc dan ganti konten dengan kode berikut
    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.");
                    }
                }
            }        
        }
    }

Menggunakan Layanan dari Aplikasi Konsol

Mari kita buat aplikasi konsol yang menggunakan layanan kami.

  • File -> Baru -> Proyek...
  • Pilih Visual C# dari panel kiri lalu Aplikasi Konsol
  • Masukkan STESample.ConsoleTest sebagai nama dan klik OK
  • Menambahkan referensi ke proyek STESample.Entities

Kami memerlukan referensi layanan ke layanan WCF kami

  • Klik kanan proyek STESample.ConsoleTest di Penjelajah Solusi dan pilih Tambahkan Referensi Layanan...
  • Klik Temukan
  • Masukkan BloggingService sebagai namespace layanan dan klik OK

Sekarang kita dapat menulis beberapa kode untuk menggunakan layanan.

  • Buka Program.cs dan ganti konten dengan kode berikut.
    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);
                }
            }
        }
    }

Anda sekarang dapat menjalankan aplikasi untuk melihatnya beraksi.

  • Klik kanan proyek STESample.ConsoleTest di Penjelajah Solusi dan pilih Debug -> Mulai instans baru

Anda akan melihat output berikut saat aplikasi dijalankan.

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

Mengonsumsi Layanan dari Aplikasi WPF

Mari kita buat aplikasi WPF yang menggunakan layanan kami.

  • File -> Baru -> Proyek...
  • Pilih Visual C# dari panel kiri lalu Aplikasi WPF
  • Masukkan STESample.WPFTest sebagai nama dan klik OK
  • Menambahkan referensi ke proyek STESample.Entities

Kami memerlukan referensi layanan ke layanan WCF kami

  • Klik kanan proyek STESample.WPFTest di Penjelajah Solusi dan pilih Tambahkan Referensi Layanan...
  • Klik Temukan
  • Masukkan BloggingService sebagai namespace layanan dan klik OK

Sekarang kita dapat menulis beberapa kode untuk menggunakan layanan.

  • Buka MainWindow.xaml dan ganti konten dengan kode berikut.
    <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>
  • Buka kode di belakang untuk MainWindow (MainWindow.xaml.cs) dan ganti konten dengan kode berikut
    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();
                }
            }
        }
    }

Anda sekarang dapat menjalankan aplikasi untuk melihatnya beraksi.

  • Klik kanan proyek STESample.WPFTest di Penjelajah Solusi dan pilih Debug -> Mulai instans baru
  • Anda dapat memanipulasi data menggunakan layar dan menyimpannya melalui layanan menggunakan tombol Simpan

WPF Main window