Aracılığıyla paylaş


Entity Framework 4.0 ve ObjectDataSource Denetimini Kullanma, Bölüm 2: İş Mantığı Katmanı ve Birim Testleri Ekleme

tarafından Tom Dykstra

Bu öğretici serisi , Entity Framework 4.0 ile Çalışmaya Başlama öğretici serisi tarafından oluşturulan Contoso Üniversitesi web uygulamasını oluşturur. Önceki öğreticileri tamamlamadıysanız, bu öğreticinin başlangıç noktası olarak oluşturduğunuz uygulamayı indirebilirsiniz . Öğretici serisinin tamamı tarafından oluşturulan uygulamayı da indirebilirsiniz. Öğreticiler hakkında sorularınız varsa bunları ASP.NET Entity Framework forumu'na gönderebilirsiniz.

Önceki öğreticide Entity Framework ve ObjectDataSource denetimi kullanarak n katmanlı bir web uygulaması oluşturdunuz. Bu öğretici, iş mantığı katmanını (BLL) ve veri erişim katmanını (DAL) ayrı tutarken iş mantığı eklemeyi ve BLL için otomatik birim testleri oluşturmayı gösterir.

Bu öğreticide aşağıdaki görevleri tamamlayacaksınız:

  • İhtiyacınız olan veri erişim yöntemlerini bildiren bir depo arabirimi oluşturun.
  • Depo sınıfına depo arabirimini uygulayın.
  • Veri erişim işlevlerini gerçekleştirmek için depo sınıfını çağıran bir iş mantığı sınıfı oluşturun.
  • ObjectDataSource Denetimi depo sınıfı yerine iş mantığı sınıfına bağlayın.
  • Birim testi projesi ve veri deposu için bellek içi koleksiyonlar kullanan bir depo sınıfı oluşturun.
  • İş mantığı sınıfına eklemek istediğiniz iş mantığı için bir birim testi oluşturun, ardından testi çalıştırın ve başarısız olduğunu görün.
  • İş mantığı sınıfında iş mantığını uygulayın, ardından birim testini yeniden çalıştırın ve geçtiğini görün.

Önceki öğreticide oluşturduğunuz Departments.aspx ve DepartmentsAdd.aspx sayfalarıyla çalışacaksınız.

Depo Arabirimi Oluşturma

İlk olarak depo arabirimini oluşturacaksınız.

Resim08

DAL klasöründe yeni bir sınıf dosyası oluşturun, ISchoolRepository.cs olarak adlandırın ve mevcut kodu aşağıdaki kodla değiştirin:

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();
    }
}

Arabirimi, depo sınıfında oluşturduğunuz crud (oluşturma, okuma, güncelleştirme, silme) yöntemlerinin her biri için bir yöntem tanımlar.

SchoolRepositorySchoolRepository.cs dosyasındaki sınıfında, bu sınıfın arabirimini uyguladığını ISchoolRepository belirtin:

public class SchoolRepository : IDisposable, ISchoolRepository

Business-Logic Sınıfı Oluşturma

Ardından iş mantığı sınıfını oluşturacaksınız. Bunu, denetim tarafından ObjectDataSource yürütülecek iş mantığını ekleyebilmeniz için yaparsınız, ancak henüz bunu yapmazsınız. Şimdilik, yeni iş mantığı sınıfı yalnızca depoyla aynı CRUD işlemlerini gerçekleştirecektir.

Resim09

Yeni bir klasör oluşturun ve BLL olarak adlandırlayın. (Gerçek dünyadaki bir uygulamada iş mantığı katmanı genellikle ayrı bir proje olan sınıf kitaplığı olarak uygulanır, ancak bu öğreticiyi basit tutmak için BLL sınıfları proje klasöründe tutulur.)

BLL klasöründe yeni bir sınıf dosyası oluşturun, SchoolBL.cs olarak adlandırın ve mevcut kodu aşağıdaki kodla değiştirin:

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);
        }

    }
}

Bu kod daha önce depo sınıfında gördüğünüz CRUD yöntemlerini oluşturur, ancak Entity Framework yöntemlerine doğrudan erişmek yerine depo sınıfı yöntemlerini çağırır.

Depo sınıfına başvuru tutan sınıf değişkeni bir arabirim türü olarak tanımlanır ve depo sınıfını oluşturan kod iki oluşturucuda yer alır. Parametresiz oluşturucu denetim tarafından ObjectDataSource kullanılır. Daha önce oluşturduğunuz sınıfının bir örneğini SchoolRepository oluşturur. Diğer oluşturucu, iş mantığı sınıfını başlatan kodun depo arabirimini uygulayan herhangi bir nesneyi geçirmesine izin verir.

Depo sınıfını ve iki oluşturucuyu çağıran CRUD yöntemleri, seçtiğiniz arka uç veri deposuyla iş mantığı sınıfını kullanmayı mümkün hale getirir. İş mantığı sınıfının çağırdığı sınıfın verileri nasıl kalıcı hale geldiğinin farkında olması gerekmez. (Buna genellikle kalıcılık cehalet denir.) Bu, iş mantığı sınıfını verileri depolamak için bellek List içi koleksiyonlar gibi basit bir öğe kullanan bir depo uygulamasına bağlayabildiğiniz için birim testini kolaylaştırır.

Not

Teknik olarak varlık nesneleri, Entity Framework'ün EntityObject sınıfından devralan sınıflardan örneklendikleri için yine de kalıcılık bilgisi içermez. Tam kalıcılık yoksayma için, sınıfından EntityObject devralan nesnelerin yerine düz eski CLR nesnelerini veya POCO'ları kullanabilirsiniz. POCO'ları kullanmak bu öğreticinin kapsamı dışındadır. Daha fazla bilgi için MSDN web sitesinde Test edilebilirlik ve Entity Framework 4.0'a bakın.)

Artık denetimleri depo yerine iş mantığı sınıfına bağlayabilir ObjectDataSource ve her şeyin daha önce olduğu gibi çalıştığını doğrulayabilirsiniz.

Departments.aspx ve DepartmentsAdd.aspx'da her oluşumunu TypeName="ContosoUniversity.DAL.SchoolRepository"TypeName="ContosoUniversity.BLL.SchoolBL"olarak değiştirin. (Tümünde dört örnek vardır.)

Daha önce olduğu gibi çalıştıklarını doğrulamak için Departments.aspx ve DepartmentsAdd.aspx sayfalarını çalıştırın.

Resim01

Resim02

Unit-Test Proje ve Depo Uygulaması Oluşturma

Test Projesi şablonunu kullanarak çözüme yeni bir proje ekleyin ve adını verinContosoUniversity.Tests.

Test projesinde öğesine bir başvuru System.Data.Entity ekleyin ve projeye bir proje başvurusu ContosoUniversity ekleyin.

Artık birim testleriyle kullanacağınız depo sınıfını oluşturabilirsiniz. Bu deponun veri deposu sınıfı içinde olacaktır.

Resim12

Test projesinde yeni bir sınıf dosyası oluşturun, mockSchoolRepository.cs olarak adlandırın ve mevcut kodu aşağıdaki kodla değiştirin:

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()
        {
            
        }
    }
}

Bu depo sınıfı, Entity Framework'e doğrudan erişen ile aynı CRUD yöntemlerine sahiptir, ancak bir veritabanı yerine bellekteki koleksiyonlarla çalışır List . Bu, bir test sınıfının iş mantığı sınıfı için birim testlerini ayarlamasını ve doğrulamasını kolaylaştırır.

Birim Testleri Oluşturma

Test projesi şablonu sizin için bir saplama birim testi sınıfı oluşturdu ve sonraki göreviniz, iş mantığı sınıfına eklemek istediğiniz iş mantığı için bu sınıfa birim testi yöntemleri ekleyerek bu sınıfı değiştirmektir.

Resim13

Contoso Üniversitesi'nde her bir eğitmen yalnızca tek bir bölümün yöneticisi olabilir ve bu kuralı uygulamak için iş mantığı eklemeniz gerekir. İlk olarak testleri ekleyip başarısız olduğunu görmek için testleri çalıştıracaksınız. Ardından kodu ekleyecek ve testlerin başarılı olduğunu görmek için testleri yeniden çalıştıracaksınız.

UnitTest1.cs dosyasını açın ve ContosoUniversity projesinde oluşturduğunuz iş mantığı ve veri erişim katmanları için deyimler ekleyinusing:

using ContosoUniversity.BLL;
using ContosoUniversity.DAL;

TestMethod1 yöntemini aşağıdaki yöntemlerle değiştirin:

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);
}

yöntemi, CreateSchoolBL birim testi projesi için oluşturduğunuz depo sınıfının bir örneğini oluşturur ve daha sonra iş mantığı sınıfının yeni bir örneğine geçirir. Yöntemi daha sonra test yöntemlerinde kullanabileceğiniz üç departman eklemek için iş mantığı sınıfını kullanır.

Test yöntemleri, birisi mevcut bir departmanla aynı yöneticiye sahip yeni bir bölüm eklemeye çalışırsa veya bir bölüm yöneticisini zaten başka bir departmanın yöneticisi olan bir kişinin kimliğine ayarlayarak güncelleştirmeye çalışırsa iş mantığı sınıfının özel durum oluşturduğunu doğrular.

Özel durum sınıfını henüz oluşturmadığınız için bu kod derlenmez. Derlemek için sağ tıklayıp Oluştur'u DuplicateAdministratorException ve ardından Sınıf'ı seçin.

Sınıf alt menüsünde Oluştur'un seçili olduğunu gösteren ekran görüntüsü.

Bu, test projesinde ana projede özel durum sınıfını oluşturduktan sonra silebileceğiniz bir sınıf oluşturur. ve iş mantığını uyguladı.

Test projesini çalıştırın. Beklendiği gibi testler başarısız olur.

Resim03

Test Geçişi Yapmak için İş Mantığı Ekleme

Ardından, zaten başka bir departmanın yöneticisi olan bir departmanın yöneticisi olarak ayarlanmasını imkansız hale getiren iş mantığını uygulayacaksınız. İş mantığı katmanından bir özel durum oluşturur ve kullanıcı bir departmanı düzenlerse ve zaten yönetici olan birini seçtikten sonra Güncelleştir'e tıklarsa sunu katmanında yakalarsınız. (Sayfayı işlemeden önce zaten yönetici olan eğitmenleri açılan listeden kaldırabilirsiniz, ancak buradaki amaç iş mantığı katmanıyla çalışmaktır.)

Bir kullanıcı bir eğitmeni birden fazla departmanın yöneticisi yapmaya çalıştığında oluşturabileceğiniz özel durum sınıfını oluşturarak başlayın. Ana projede , BLL klasöründe yeni bir sınıf dosyası oluşturun, dosyayı DuplicateAdministratorException.cs olarak adlandırın ve mevcut kodu aşağıdaki kodla değiştirin:

using System;

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

Şimdi derleme yapabilmek için daha önce test projesinde oluşturduğunuz geçici DuplicateAdministratorException.cs dosyasını silin.

Ana projede SchoolBL.cs dosyasını açın ve doğrulama mantığını içeren aşağıdaki yöntemi ekleyin. (Kod, daha sonra oluşturacağınız bir yönteme başvurur.)

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));
        }
    }
}

Başka bir departmanın zaten aynı yöneticiye sahip olup olmadığını denetlemek için varlıkları eklerken veya güncelleştirirken Department bu yöntemi çağırırsınız.

Kod, eklenen veya güncelleştirilen varlıkla aynı Administrator özellik değerine sahip bir Department varlığı veritabanında aramak için bir yöntem çağırır. Bir tane bulunursa, kod bir özel durum oluşturur. Eklenen veya güncelleştirilen varlığın değeri yoksa Administrator doğrulama denetimi gerekmez ve yöntem bir güncelleştirme sırasında çağrılırsa ve Department bulunan varlık güncelleştirilen varlıkla eşleşirse Department özel durum oluşturmaz.

ve Update yöntemlerinden Insert yeni yöntemi çağırın:

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

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

ISchoolRepository.cs dosyasına yeni veri erişim yöntemi için aşağıdaki bildirimi ekleyin:

IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator);

SchoolRepository.cs dosyasına aşağıdaki using deyimi ekleyin:

using System.Data.Objects;

SchoolRepository.cs dosyasına aşağıdaki yeni veri erişim yöntemini ekleyin:

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();
}

Bu kod, Department belirtilen yöneticiye sahip varlıkları alır. Yalnızca bir departman bulunmalıdır (varsa). Ancak, veritabanında hiçbir kısıtlama yerleşik olmadığından, birden çok departmanın bulunması durumunda dönüş türü bir koleksiyondur.

Varsayılan olarak, nesne bağlamı veritabanından varlıkları aldığında, bunları nesne durum yöneticisinde izler. MergeOption.NoTracking parametresi, bu izlemenin bu sorgu için yapılmayacağını belirtir. Bu gereklidir çünkü sorgu, güncelleştirmeye çalıştığınız tam varlığı döndürebilir ve bu varlığı ekleyemeyebilirsiniz. Örneğin, Departments.aspx sayfasında Geçmiş bölümünü düzenler ve yöneticiyi değiştirmeden bırakırsanız, bu sorgu Geçmiş bölümünü döndürür. Ayarlanmadıysa NoTracking , nesne bağlamı zaten nesne durum yöneticisinde Geçmiş departmanı varlığına sahip olacaktır. Ardından görünüm durumundan yeniden oluşturulan Geçmiş departmanı varlığını eklediğinizde, nesne bağlamı ifadesini "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key"içeren bir özel durum oluşturur.

(belirtmeye MergeOption.NoTrackingalternatif olarak, yalnızca bu sorgu için yeni bir nesne bağlamı oluşturabilirsiniz. Yeni nesne bağlamı kendi nesne durum yöneticisine sahip olacağından, yöntemini çağırdığınızda Attach çakışma olmaz. Yeni nesne bağlamı, meta verileri ve veritabanı bağlantısını özgün nesne bağlamıyla paylaşır, bu nedenle bu alternatif yaklaşımın performans cezası en düşük düzeyde olur. Ancak burada gösterilen yaklaşım, diğer bağlamlarda NoTracking yararlı bulacağınız seçeneği tanıtır. Bu NoTracking seçenek, bu serinin sonraki öğreticilerinde daha ayrıntılı olarak ele alınmalıdır.)

Test projesinde mockSchoolRepository.cs dosyasına yeni veri erişim yöntemini ekleyin:

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

Bu kod, proje deposunun LINQ to Entities kullandığı veri seçimini ContosoUniversity gerçekleştirmek için LINQ kullanır.

Test projesini yeniden çalıştırın. Bu kez testler geçer.

Resim04

ObjectDataSource Özel Durumlarını İşleme

Projede ContosoUniversityDepartments.aspx sayfasını çalıştırın ve bir bölümün yöneticisini zaten başka bir departmanın yöneticisi olan biriyle değiştirmeye çalışın. (Veritabanı geçersiz verilerle önceden yüklenmiş olarak geldiğinden, yalnızca bu öğretici sırasında eklediğiniz bölümleri düzenleyebildiğinizi unutmayın.) Aşağıdaki sunucu hata sayfasını alırsınız:

Resim05

Kullanıcıların bu tür bir hata sayfasını görmesini istemediğiniz için hata işleme kodu eklemeniz gerekir. Departments.aspx dosyasını açın ve olayı DepartmentsObjectDataSourceiçin OnUpdated bir işleyici belirtin. Açma ObjectDataSource etiketi artık aşağıdaki örneğe benzer.

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

Departments.aspx.cs dosyasına aşağıdaki using deyimi ekleyin:

using ContosoUniversity.BLL;

Olay için aşağıdaki işleyiciyi Updated ekleyin:

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 Denetim, güncelleştirmeyi gerçekleştirmeye çalıştığında bir özel durum yakalarsa, olay bağımsız değişkenindeki (e) özel durumu bu işleyiciye geçirir. İşleyicideki kod, özel durumun yinelenen yönetici özel durumu olup olmadığını denetler. Bu durumda kod, denetimin görüntülenmesi için ValidationSummary bir hata iletisi içeren bir doğrulayıcı denetimi oluşturur.

Sayfayı çalıştırın ve birini yeniden iki departmanın yöneticisi yapmayı deneyin. Bu kez ValidationSummary denetim bir hata iletisi görüntüler.

Resim06

DepartmentsAdd.aspx sayfasında da benzer değişiklikler yapın. DepartmentsAdd.aspx'da, olayının OnInserted işleyicisini DepartmentsObjectDataSourcebelirtin. Sonuçta elde edilen işaretleme aşağıdaki örneğe benzer olacaktır.

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

DepartmentsAdd.aspx.cs dosyasına aynı using deyimi ekleyin:

using ContosoUniversity.BLL;

Aşağıdaki olay işleyicisini ekleyin:

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;
        }
    }
}

Artık DepartmentsAdd.aspx.cs sayfasını test edebilir ve bir kişiyi birden fazla departmanın yöneticisi yapma girişimlerini de doğru işlediğini doğrulayabilirsiniz.

Bu, Denetimi Entity Framework ile kullanmak için depo desenini ObjectDataSource uygulamaya giriş işlemini tamamlar. Depo deseni ve test edilebilirliği hakkında daha fazla bilgi için MSDN test edilebilirliği ve Entity Framework 4.0 teknik incelemesine bakın.

Aşağıdaki öğreticide, uygulamaya sıralama ve filtreleme işlevinin nasıl ekleneceğini göreceksiniz.