Bagikan melalui


Menggunakan Entity Framework 4.0 dan ObjectDataSource Control, Bagian 2: Menambahkan Lapisan Logika Bisnis dan Pengujian Unit

oleh Tom Dykstra

Seri tutorial ini dibangun pada aplikasi web Contoso University yang dibuat oleh seri tutorial Memulai Entity Framework 4.0 . Jika Anda tidak menyelesaikan tutorial sebelumnya, sebagai titik awal untuk tutorial ini, Anda dapat mengunduh aplikasi yang akan Anda buat. Anda juga dapat mengunduh aplikasi yang dibuat oleh seri tutorial lengkap. Jika Anda memiliki pertanyaan tentang tutorial, Anda dapat mempostingnya ke forum ASP.NET Entity Framework.

Dalam tutorial sebelumnya Anda membuat aplikasi web n-tingkat menggunakan Kerangka Kerja Entitas dan ObjectDataSource kontrol. Tutorial ini menunjukkan cara menambahkan logika bisnis sambil menjaga lapisan logika bisnis (BLL) dan lapisan akses data (DAL) terpisah, dan menunjukkan cara membuat pengujian unit otomatis untuk BLL.

Dalam tutorial ini Anda akan menyelesaikan tugas-tugas berikut:

  • Buat antarmuka repositori yang mendeklarasikan metode akses data yang Anda butuhkan.
  • Terapkan antarmuka repositori di kelas repositori.
  • Buat kelas logika bisnis yang memanggil kelas repositori untuk melakukan fungsi akses data.
  • Sambungkan ObjectDataSource kontrol ke kelas logika bisnis alih-alih ke kelas repositori.
  • Buat proyek pengujian unit dan kelas repositori yang menggunakan koleksi dalam memori untuk penyimpanan datanya.
  • Buat pengujian unit untuk logika bisnis yang ingin Anda tambahkan ke kelas logika bisnis, lalu jalankan pengujian dan lihat gagal.
  • Terapkan logika bisnis di kelas logika bisnis, lalu jalankan kembali pengujian unit dan lihat lulus.

Anda akan bekerja dengan halaman Departments.aspx dan DepartmentsAdd.aspx yang Anda buat di tutorial sebelumnya.

Membuat Antarmuka Repositori

Anda akan mulai dengan membuat antarmuka repositori.

Gambar08

Di folder DAL , buat file kelas baru, beri nama ISchoolRepository.cs, dan ganti kode yang ada dengan kode berikut:

using System;
using System.Collections.Generic;

namespace ContosoUniversity.DAL
{
    public interface ISchoolRepository : IDisposable
    {
        IEnumerable<Department> GetDepartments();
        void InsertDepartment(Department department);
        void DeleteDepartment(Department department);
        void UpdateDepartment(Department department, Department origDepartment);
        IEnumerable<InstructorName> GetInstructorNames();
    }
}

Antarmuka mendefinisikan satu metode untuk setiap metode CRUD (buat, baca, perbarui, hapus) yang Anda buat di kelas repositori.

SchoolRepository Di kelas di SchoolRepository.cs, tunjukkan bahwa kelas ini mengimplementasikan ISchoolRepository antarmuka:

public class SchoolRepository : IDisposable, ISchoolRepository

Membuat Kelas Business-Logic

Selanjutnya, Anda akan membuat kelas logika bisnis. Anda melakukan ini sehingga Anda dapat menambahkan logika bisnis yang akan dijalankan oleh ObjectDataSource kontrol, meskipun Anda belum akan melakukannya. Untuk saat ini, kelas logika bisnis baru hanya akan melakukan operasi CRUD yang sama dengan yang dilakukan repositori.

Gambar09

Buat folder baru dan beri nama BLL. (Dalam aplikasi dunia nyata, lapisan logika bisnis biasanya akan diimplementasikan sebagai pustaka kelas - proyek terpisah - tetapi untuk menjaga tutorial ini sederhana, kelas BLL akan disimpan dalam folder proyek.)

Di folder BLL , buat file kelas baru, beri nama SchoolBL.cs, dan ganti kode yang ada dengan kode berikut:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using ContosoUniversity.DAL;

namespace ContosoUniversity.BLL
{
    public class SchoolBL : IDisposable
    {
        private ISchoolRepository schoolRepository;

        public SchoolBL()
        {
            this.schoolRepository = new SchoolRepository();
        }

        public SchoolBL(ISchoolRepository schoolRepository)
        {
            this.schoolRepository = schoolRepository;
        }

        public IEnumerable<Department> GetDepartments()
        {
            return schoolRepository.GetDepartments();
        }

        public void InsertDepartment(Department department)
        {
            try
            {
                schoolRepository.InsertDepartment(department);
            }
            catch (Exception ex)
            {
                //Include catch blocks for specific exceptions first,
                //and handle or log the error as appropriate in each.
                //Include a generic catch block like this one last.
                throw ex;
            }
        }

        public void DeleteDepartment(Department department)
        {
            try
            {
                schoolRepository.DeleteDepartment(department);
            }
            catch (Exception ex)
            {
                //Include catch blocks for specific exceptions first,
                //and handle or log the error as appropriate in each.
                //Include a generic catch block like this one last.
                throw ex;
            }
        }

        public void UpdateDepartment(Department department, Department origDepartment)
        {
            try
            {
                schoolRepository.UpdateDepartment(department, origDepartment);
            }
            catch (Exception ex)
            {
                //Include catch blocks for specific exceptions first,
                //and handle or log the error as appropriate in each.
                //Include a generic catch block like this one last.
                throw ex;
            }

        }

        public IEnumerable<InstructorName> GetInstructorNames()
        {
            return schoolRepository.GetInstructorNames();
        }

        private bool disposedValue = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposedValue)
            {
                if (disposing)
                {
                    schoolRepository.Dispose();
                }
            }
            this.disposedValue = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

    }
}

Kode ini membuat metode CRUD yang sama dengan yang Anda lihat sebelumnya di kelas repositori, tetapi alih-alih mengakses metode Kerangka Kerja Entitas secara langsung, kode ini memanggil metode kelas repositori.

Variabel kelas yang menyimpan referensi ke kelas repositori didefinisikan sebagai jenis antarmuka, dan kode yang membuat instans kelas repositori terkandung dalam dua konstruktor. Konstruktor tanpa parameter akan digunakan oleh ObjectDataSource kontrol. Ini membuat instans SchoolRepository kelas yang Anda buat sebelumnya. Konstruktor lain memungkinkan kode apa pun yang membuat instans kelas logika bisnis untuk meneruskan objek apa pun yang mengimplementasikan antarmuka repositori.

Metode CRUD yang memanggil kelas repositori dan kedua konstruktor memungkinkan untuk menggunakan kelas logika bisnis dengan penyimpanan data back-end apa pun yang Anda pilih. Kelas logika bisnis tidak perlu menyadari bagaimana kelas yang dipanggilnya mempertahankan data. (Ini sering disebut ketidaktahuan persistensi.) Ini memfasilitasi pengujian unit, karena Anda dapat menghubungkan kelas logika bisnis ke implementasi repositori yang menggunakan sesuatu sesingkat koleksi dalam memori List untuk menyimpan data.

Catatan

Secara teknis, objek entitas masih tidak bersifat tidak tahu persistensi, karena objek tersebut dibuat dari kelas yang mewarisi dari kelas Entity Framework EntityObject . Untuk ketidaktahuan persistensi lengkap, Anda dapat menggunakan objek CLR lama biasa, atau POCO, sebagai pengganti objek yang mewarisi dari EntityObject kelas . Menggunakan POCO berada di luar cakupan tutorial ini. Untuk informasi selengkapnya, lihat Kemampuan Pengujian dan Kerangka Kerja Entitas 4.0 di situs web MSDN.)

Sekarang Anda dapat menyambungkan ObjectDataSource kontrol ke kelas logika bisnis alih-alih ke repositori dan memverifikasi bahwa semuanya berfungsi seperti sebelumnya.

Di Departments.aspx dan DepartmentsAdd.aspx, ubah setiap kemunculan menjadi TypeName="ContosoUniversity.DAL.SchoolRepository"TypeName="ContosoUniversity.BLL.SchoolBL". (Ada empat instans di semua.)

Jalankan halaman Departments.aspx dan DepartmentsAdd.aspx untuk memverifikasi bahwa mereka masih berfungsi seperti yang mereka lakukan sebelumnya.

Gambar01

Gambar02

Membuat Implementasi Proyek dan Repositori Unit-Test

Tambahkan proyek baru ke solusi menggunakan templat Proyek Pengujian , dan beri nama ContosoUniversity.Tests.

Dalam proyek pengujian, tambahkan referensi ke System.Data.Entity dan tambahkan referensi proyek ke ContosoUniversity proyek.

Anda sekarang dapat membuat kelas repositori yang akan Anda gunakan dengan pengujian unit. Penyimpanan data untuk repositori ini akan berada dalam kelas .

Gambar12

Dalam proyek pengujian, buat file kelas baru, beri nama MockSchoolRepository.cs, dan ganti kode yang ada dengan kode berikut:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ContosoUniversity.DAL;
using ContosoUniversity.BLL;

namespace ContosoUniversity.Tests
{
    class MockSchoolRepository : ISchoolRepository, IDisposable
    {
        List<Department> departments = new List<Department>();
        List<InstructorName> instructors = new List<InstructorName>();

        public IEnumerable<Department> GetDepartments()
        {
            return departments;
        }

        public void InsertDepartment(Department department)
        {
            departments.Add(department);
        }

        public void DeleteDepartment(Department department)
        {
            departments.Remove(department);
        }

        public void UpdateDepartment(Department department, Department origDepartment)
        {
            departments.Remove(origDepartment);
            departments.Add(department);
        }

        public IEnumerable<InstructorName> GetInstructorNames()
        {
            return instructors;
        }

        public void Dispose()
        {
            
        }
    }
}

Kelas repositori ini memiliki metode CRUD yang sama dengan yang mengakses Kerangka Kerja Entitas secara langsung, tetapi mereka bekerja dengan List koleksi dalam memori alih-alih dengan database. Ini memudahkan kelas pengujian untuk menyiapkan dan memvalidasi pengujian unit untuk kelas logika bisnis.

Membuat Pengujian Unit

Templat Uji proyek membuat kelas pengujian unit stub untuk Anda, dan tugas Anda berikutnya adalah memodifikasi kelas ini dengan menambahkan metode pengujian unit ke dalamnya untuk logika bisnis yang ingin Anda tambahkan ke kelas logika bisnis.

Gambar13

Di Contoso University, setiap instruktur individu hanya dapat menjadi administrator dari satu departemen, dan Anda perlu menambahkan logika bisnis untuk menegakkan aturan ini. Anda akan mulai dengan menambahkan pengujian dan menjalankan pengujian untuk melihatnya gagal. Anda kemudian akan menambahkan kode dan menjalankan ulang pengujian, mengharapkan untuk melihatnya lulus.

Buka file UnitTest1.cs dan tambahkan using pernyataan untuk logika bisnis dan lapisan akses data yang Anda buat di proyek ContosoUniversity:

using ContosoUniversity.BLL;
using ContosoUniversity.DAL;

TestMethod1 Ganti metode dengan metode berikut:

private SchoolBL CreateSchoolBL()
{
    var schoolRepository = new MockSchoolRepository();
    var schoolBL = new SchoolBL(schoolRepository);
    schoolBL.InsertDepartment(new Department() { Name = "First Department", DepartmentID = 0, Administrator = 1, Person = new Instructor () { FirstMidName = "Admin", LastName = "One" } });
    schoolBL.InsertDepartment(new Department() { Name = "Second Department", DepartmentID = 1, Administrator = 2, Person = new Instructor() { FirstMidName = "Admin", LastName = "Two" } });
    schoolBL.InsertDepartment(new Department() { Name = "Third Department", DepartmentID = 2, Administrator = 3, Person = new Instructor() { FirstMidName = "Admin", LastName = "Three" } });
    return schoolBL;
}

[TestMethod]
[ExpectedException(typeof(DuplicateAdministratorException))]
public void AdministratorAssignmentRestrictionOnInsert()
{
    var schoolBL = CreateSchoolBL();
    schoolBL.InsertDepartment(new Department() { Name = "Fourth Department", DepartmentID = 3, Administrator = 2, Person = new Instructor() { FirstMidName = "Admin", LastName = "Two" } });
}

[TestMethod]
[ExpectedException(typeof(DuplicateAdministratorException))]
public void AdministratorAssignmentRestrictionOnUpdate()
{
    var schoolBL = CreateSchoolBL();
    var origDepartment = (from d in schoolBL.GetDepartments()
                          where d.Name == "Second Department"
                          select d).First();
    var department = (from d in schoolBL.GetDepartments()
                          where d.Name == "Second Department"
                          select d).First();
    department.Administrator = 1;
    schoolBL.UpdateDepartment(department, origDepartment);
}

Metode ini CreateSchoolBL membuat instans kelas repositori yang Anda buat untuk proyek pengujian unit, yang kemudian diteruskan ke instans baru kelas logika bisnis. Metode ini kemudian menggunakan kelas logika bisnis untuk menyisipkan tiga departemen yang dapat Anda gunakan dalam metode pengujian.

Metode pengujian memverifikasi bahwa kelas logika bisnis melempar pengecualian jika seseorang mencoba menyisipkan departemen baru dengan administrator yang sama dengan departemen yang ada, atau jika seseorang mencoba memperbarui administrator departemen dengan mengaturnya ke ID seseorang yang sudah menjadi administrator departemen lain.

Anda belum membuat kelas pengecualian, sehingga kode ini tidak akan dikompilasi. Untuk mengkompilasinya, klik DuplicateAdministratorException kanan dan pilih Hasilkan, lalu Kelas.

Cuplikan layar yang memperlihatkan Buat dipilih di submenu Kelas.

Ini membuat kelas dalam proyek pengujian yang dapat Anda hapus setelah Anda membuat kelas pengecualian di proyek utama. dan menerapkan logika bisnis.

Jalankan proyek pengujian. Seperti yang diharapkan, tes gagal.

Gambar03

Menambahkan Logika Bisnis untuk Membuat Uji Lulus

Selanjutnya, Anda akan menerapkan logika bisnis yang membuatnya tidak mungkin ditetapkan sebagai administrator departemen seseorang yang sudah menjadi administrator departemen lain. Anda akan memberikan pengecualian dari lapisan logika bisnis, lalu menangkapnya di lapisan presentasi jika pengguna mengedit departemen dan mengklik Perbarui setelah memilih seseorang yang sudah menjadi administrator. (Anda juga dapat menghapus instruktur dari daftar drop-down yang sudah menjadi administrator sebelum Merender halaman, tetapi tujuannya di sini adalah untuk bekerja dengan lapisan logika bisnis.)

Mulailah dengan membuat kelas pengecualian yang akan Anda lempar saat pengguna mencoba membuat instruktur administrator lebih dari satu departemen. Dalam proyek utama, buat file kelas baru di folder BLL , beri nama DuplicateAdministratorException.cs, dan ganti kode yang ada dengan kode berikut:

using System;

namespace ContosoUniversity.BLL
{
    public class DuplicateAdministratorException : Exception
    {
        public DuplicateAdministratorException(string message)
            : base(message)
        {
        }
    }
}

Sekarang hapus file DuplicateAdministratorException.cs sementara yang Anda buat di proyek pengujian sebelumnya agar dapat dikompilasi.

Dalam proyek utama, buka file SchoolBL.cs dan tambahkan metode berikut yang berisi logika validasi. (Kode mengacu pada metode yang akan Anda buat nanti.)

private void ValidateOneAdministratorAssignmentPerInstructor(Department department)
{
    if (department.Administrator != null)
    {
        var duplicateDepartment = schoolRepository.GetDepartmentsByAdministrator(department.Administrator.GetValueOrDefault()).FirstOrDefault();
        if (duplicateDepartment != null && duplicateDepartment.DepartmentID != department.DepartmentID)
        {
            throw new DuplicateAdministratorException(String.Format(
                "Instructor {0} {1} is already administrator of the {2} department.", 
                duplicateDepartment.Person.FirstMidName, 
                duplicateDepartment.Person.LastName, 
                duplicateDepartment.Name));
        }
    }
}

Anda akan memanggil metode ini saat menyisipkan atau memperbarui Department entitas untuk memeriksa apakah departemen lain sudah memiliki administrator yang sama.

Kode memanggil metode untuk mencari database untuk Department entitas yang memiliki nilai properti yang sama Administrator dengan entitas yang dimasukkan atau diperbarui. Jika ditemukan, kode akan melemparkan pengecualian. Tidak ada pemeriksaan validasi yang diperlukan jika entitas yang dimasukkan atau diperbarui tidak Administrator memiliki nilai, dan tidak ada pengecualian yang dilemparkan jika metode dipanggil selama pembaruan dan entitas yang Department ditemukan cocok dengan entitas yang Department diperbarui.

Panggil metode baru dari Insert metode dan Update :

public void InsertDepartment(Department department)
{
    ValidateOneAdministratorAssignmentPerInstructor(department);
    try
    ...

public void UpdateDepartment(Department department, Department origDepartment)
{
    ValidateOneAdministratorAssignmentPerInstructor(department);
    try
    ...

Di ISchoolRepository.cs, tambahkan deklarasi berikut untuk metode akses data baru:

IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator);

Di SchoolRepository.cs, tambahkan pernyataan berikut using :

using System.Data.Objects;

Di SchoolRepository.cs, tambahkan metode akses data baru berikut ini:

public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
    return new ObjectQuery<Department>("SELECT VALUE d FROM Departments as d", context, MergeOption.NoTracking).Include("Person").Where(d => d.Administrator == administrator).ToList();
}

Kode ini mengambil Department entitas yang memiliki administrator tertentu. Hanya satu departemen yang harus ditemukan (jika ada). Namun, karena tidak ada batasan yang dibangun ke dalam database, jenis pengembalian adalah koleksi jika beberapa departemen ditemukan.

Secara default, ketika konteks objek mengambil entitas dari database, konteks tersebut melacaknya di manajer status objeknya. Parameter MergeOption.NoTracking menentukan bahwa pelacakan ini tidak akan dilakukan untuk kueri ini. Ini diperlukan karena kueri mungkin mengembalikan entitas yang tepat yang coba Anda perbarui, lalu Anda tidak akan dapat melampirkan entitas tersebut. Misalnya, jika Anda mengedit departemen Riwayat di halaman Departments.aspx dan membiarkan administrator tidak berubah, kueri ini akan mengembalikan departemen Riwayat. Jika NoTracking tidak diatur, konteks objek akan sudah memiliki entitas departemen Riwayat di manajer status objeknya. Kemudian ketika Anda melampirkan entitas departemen Riwayat yang dibuat ulang dari status tampilan, konteks objek akan melemparkan pengecualian yang mengatakan "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key".

(Sebagai alternatif untuk menentukan MergeOption.NoTracking, Anda dapat membuat konteks objek baru hanya untuk kueri ini. Karena konteks objek baru akan memiliki manajer status objeknya sendiri, tidak akan ada konflik ketika Anda memanggil Attach metode . Konteks objek baru akan berbagi metadata dan koneksi database dengan konteks objek asli, sehingga penalti performa pendekatan alternatif ini akan minimal. Pendekatan yang ditunjukkan di sini, bagaimanapun, memperkenalkan NoTracking opsi , yang akan Anda temukan berguna dalam konteks lain. Opsi NoTracking ini dibahas lebih lanjut dalam tutorial selanjutnya dalam seri ini.)

Dalam proyek pengujian, tambahkan metode akses data baru ke MockSchoolRepository.cs:

public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
    return (from d in departments
            where d.Administrator == administrator
            select d);
}

Kode ini menggunakan LINQ untuk melakukan pemilihan data yang sama dengan ContosoUniversity repositori proyek menggunakan LINQ ke Entitas.

Jalankan proyek pengujian lagi. Kali ini tes lulus.

Gambar04

Menangani Pengecualian ObjectDataSource

ContosoUniversity Dalam proyek, jalankan halaman Departments.aspx dan coba ubah administrator untuk departemen menjadi seseorang yang sudah menjadi administrator untuk departemen lain. (Ingat bahwa Anda hanya dapat mengedit departemen yang Anda tambahkan selama tutorial ini, karena database dimuat sebelumnya dengan data yang tidak valid.) Anda mendapatkan halaman kesalahan server berikut:

Gambar05

Anda tidak ingin pengguna melihat halaman kesalahan semacam ini, jadi Anda perlu menambahkan kode penanganan kesalahan. Buka Departments.aspx dan tentukan handler untuk OnUpdated peristiwa DepartmentsObjectDataSource. Tag ObjectDataSource pembuka sekarang menyerupai contoh berikut.

<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.BLL.SchoolBL"
        DataObjectTypeName="ContosoUniversity.DAL.Department" 
        SelectMethod="GetDepartments" 
        DeleteMethod="DeleteDepartment" 
        UpdateMethod="UpdateDepartment"
        ConflictDetection="CompareAllValues"
        OldValuesParameterFormatString="orig{0}" 
        OnUpdated="DepartmentsObjectDataSource_Updated" >

Di Departments.aspx.cs, tambahkan pernyataan berikut using :

using ContosoUniversity.BLL;

Tambahkan handler berikut untuk peristiwa:Updated

protected void DepartmentsObjectDataSource_Updated(object sender, ObjectDataSourceStatusEventArgs e)
{
    if (e.Exception != null)
    {
        if (e.Exception.InnerException is DuplicateAdministratorException)
        {
            var duplicateAdministratorValidator = new CustomValidator();
            duplicateAdministratorValidator.IsValid = false;
            duplicateAdministratorValidator.ErrorMessage = "Update failed: " + e.Exception.InnerException.Message;
            Page.Validators.Add(duplicateAdministratorValidator);
            e.ExceptionHandled = true;
        }
    }
}

ObjectDataSource Jika kontrol menangkap pengecualian saat mencoba melakukan pembaruan, kontrol meneruskan pengecualian dalam argumen peristiwa (e) ke handler ini. Kode dalam handler memeriksa untuk melihat apakah pengecualiannya adalah pengecualian administrator duplikat. Jika ya, kode akan membuat kontrol validator yang berisi pesan kesalahan agar ValidationSummary kontrol ditampilkan.

Jalankan halaman dan coba jadikan seseorang sebagai administrator dua departemen lagi. Kali ValidationSummary ini kontrol menampilkan pesan kesalahan.

Gambar06

Buat perubahan serupa pada halaman DepartmentsAdd.aspx . Di DepartmentsAdd.aspx, tentukan handler untuk OnInserted peristiwa DepartmentsObjectDataSource. Markup yang dihasilkan akan menyerupai contoh berikut.

<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.BLL.SchoolBL" DataObjectTypeName="ContosoUniversity.DAL.Department" 
        InsertMethod="InsertDepartment"  
        OnInserted="DepartmentsObjectDataSource_Inserted">

Di DepartmentsAdd.aspx.cs, tambahkan pernyataan yang sama using :

using ContosoUniversity.BLL;

Tambahkan penanganan aktivitas berikut:

protected void DepartmentsObjectDataSource_Inserted(object sender, ObjectDataSourceStatusEventArgs e)
{
    if (e.Exception != null)
    {
        if (e.Exception.InnerException is DuplicateAdministratorException)
        {
            var duplicateAdministratorValidator = new CustomValidator();
            duplicateAdministratorValidator.IsValid = false;
            duplicateAdministratorValidator.ErrorMessage = "Insert failed: " + e.Exception.InnerException.Message;
            Page.Validators.Add(duplicateAdministratorValidator);
            e.ExceptionHandled = true;
        }
    }
}

Sekarang Anda dapat menguji halaman DepartmentsAdd.aspx.cs untuk memverifikasi bahwa halaman tersebut juga menangani upaya untuk menjadikan satu orang administrator lebih dari satu departemen.

Ini menyelesaikan pengenalan untuk mengimplementasikan pola repositori untuk menggunakan ObjectDataSource kontrol dengan Kerangka Kerja Entitas. Untuk informasi selengkapnya tentang pola repositori dan keterujian, lihat MSDN whitepaper Testability dan Entity Framework 4.0.

Dalam tutorial berikut, Anda akan melihat cara menambahkan fungsi pengurutan dan pemfilteran ke aplikasi.