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.
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.
SchoolRepository
SchoolRepository.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.
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.
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.
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.
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.
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.
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.NoTracking
alternatif 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.
ObjectDataSource Özel Durumlarını İşleme
Projede ContosoUniversity
Departments.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:
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ı DepartmentsObjectDataSource
iç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.
DepartmentsAdd.aspx sayfasında da benzer değişiklikler yapın. DepartmentsAdd.aspx'da, olayının OnInserted
işleyicisini DepartmentsObjectDataSource
belirtin. 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.