ASP.NET 4 Web Uygulamasında Entity Framework 4.0 ile Eşzamanlılığı İşleme
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, denetimi ve Entity Framework'i kullanarak verileri sıralamayı ObjectDataSource
ve filtrelemeyi öğrendinsiniz. Bu öğretici, Entity Framework kullanan bir ASP.NET web uygulamasında eşzamanlılığı işleme seçeneklerini gösterir. Eğitmen ofis ödevlerini güncelleştirmeye ayrılmış yeni bir web sayfası oluşturacaksınız. Bu sayfada ve daha önce oluşturduğunuz Departmanlar sayfasında eşzamanlılık sorunlarını ele alacağız.
Eşzamanlılık Çakışmaları
Bir kullanıcı kaydı düzenlediğinde ve başka bir kullanıcı ilk kullanıcının değişikliği veritabanına yazılmadan önce aynı kaydı düzenlediğinde eşzamanlılık çakışması oluşur. Bu tür çakışmaları algılamak için Entity Framework'u ayarlamazsanız, veritabanını son güncelleştiren kişi diğer kullanıcının değişikliklerinin üzerine yazar. Birçok uygulamada bu risk kabul edilebilir ve uygulamayı olası eşzamanlılık çakışmalarını işleyecek şekilde yapılandırmanız gerekmez. (Çok az kullanıcı veya birkaç güncelleştirme varsa ya da bazı değişikliklerin üzerine yazılırsa gerçekten kritik değilse eşzamanlılık programlama maliyeti avantajdan daha ağır basabilir.) Eşzamanlılık çakışmaları konusunda endişelenmeniz gerekmiyorsa bu öğreticiyi atlayabilirsiniz; serinin kalan iki öğreticisi, bu öğreticide oluşturduğunuz hiçbir şeye bağlı değildir.
Kötümser Eşzamanlılık (Kilitleme)
Uygulamanızın eşzamanlılık senaryolarında yanlışlıkla veri kaybını önlemesi gerekiyorsa, bunu gerçekleştirmenin bir yolu veritabanı kilitlerini kullanmaktır. Buna kötümser eşzamanlılık denir. Örneğin, veritabanından bir satırı okumadan önce salt okunur veya güncelleştirme erişimi için bir kilit isteyebilirsiniz. Bir satırı güncelleştirme erişimi için kilitlerseniz, başka hiçbir kullanıcının salt okunur veya güncelleştirme erişimi için satırı kilitlemesine izin verilmez, çünkü değiştirme sürecindeki verilerin bir kopyasını alabilirler. Bir satırı salt okunur erişim için kilitlerseniz, diğerleri de satırı salt okunur erişim için kilitleyebilir ancak güncelleştirme için kilitleyebilir.
Kilitleri yönetmenin bazı dezavantajları vardır. Programlamak karmaşık olabilir. Önemli veritabanı yönetim kaynakları gerektirir ve bir uygulamanın kullanıcı sayısı arttıkça performans sorunlarına neden olabilir (yani iyi ölçeklendirilemez). Bu nedenlerden dolayı, tüm veritabanı yönetim sistemleri kötümser eşzamanlılığı desteklemez. Entity Framework bunun için yerleşik destek sağlamaz ve bu öğreticide bunu nasıl uygulayabileceğiniz gösterilmez.
İyimser Eşzamanlılık
Kötümser eşzamanlılığın alternatifi iyimser eşzamanlılıktır. İyimser eşzamanlılık, eşzamanlılık çakışmalarının gerçekleşmesine izin vermek ve varsa uygun şekilde tepki vermek anlamına gelir. Örneğin, John Department.aspx sayfasını çalıştırır, Geçmiş bölümünün Düzenle bağlantısına tıklar ve Bütçe tutarını 1.000.000,00 TL'den 125.000,00 TL'ye düşürür. (John rakip bir departmanı yönetiyor ve kendi departmanı için para boşaltmak istiyor.)
John Güncelleştir'e tıklamadan önce, Jane aynı sayfayı çalıştırır, Geçmiş bölümünün Düzenle bağlantısına tıklar ve başlangıç tarihi alanını 10.01.2011'den 1/1/1999'a değiştirir. (Jane, Geçmiş bölümünü yönetiyor ve daha fazla kıdem vermek istiyor.)
John önce Güncelleştir'e tıklar, sonra Jane Güncelleştir'e tıklar. Jane'in tarayıcısı şimdi Bütçe tutarını 1.000.000.00 TL olarak listeler, ancak bu yanlıştır çünkü miktar John tarafından 125.000,00 TL olarak değiştirilmiştir.
Bu senaryoda gerçekleştirebileceğiniz eylemlerden bazıları şunlardır:
Kullanıcının hangi özelliği değiştirdiğini izleyebilir ve veritabanında yalnızca ilgili sütunları güncelleştirebilirsiniz. Örnek senaryoda, iki kullanıcı tarafından farklı özellikler güncelleştirildiğinden hiçbir veri kaybolmaz. Geçmiş bölümüne bir daha göz atarken 1/1/1999 ve 125.000,00 ABD doları görecektir.
Bu, Entity Framework'teki varsayılan davranıştır ve veri kaybına neden olabilecek çakışma sayısını önemli ölçüde azaltabilir. Ancak, bir varlığın aynı özelliğinde rakip değişiklikler yapıldığında bu davranış veri kaybını önlemez. Buna ek olarak, bu davranış her zaman mümkün değildir; saklı yordamları bir varlık türüyle eşlediğinizde, veritabanında varlıkta herhangi bir değişiklik yapıldığında varlığın tüm özellikleri güncelleştirilir.
Jane'in değişikliğinin John'un değişikliğinin üzerine yazmasına izin vekleyebilirsiniz. Jane Güncelleştir'e tıkladıktan sonra Bütçe tutarı 1.000.000,00 TL'ye geri döner. Bu, İstemci Kazanır veya Wins senaryosunda Son olarak adlandırılır. (İstemcinin değerleri, veri deposundakilerden önceliklidir.)
Jane'in değişikliğinin veritabanında güncelleştirilmesini engelleyebilirsiniz. Genellikle bir hata iletisi görüntüler, verilerin geçerli durumunu gösterir ve yine de yapmak isterse değişikliklerini yeniden girmesine izin verirsiniz. Girdisini kaydederek ve yeniden girmenize gerek kalmadan yeniden uygulama fırsatı vererek süreci daha da otomatikleştirebilirsiniz. Buna Store Wins senaryosu adı verilir. (Veri deposu değerleri, istemci tarafından gönderilen değerlerden önceliklidir.)
Eşzamanlılık Çakışmalarını Algılama
Entity Framework'te, Entity Framework'ün oluşturduğu özel durumları işleyerek OptimisticConcurrencyException
çakışmaları çözebilirsiniz. Bu özel durumların ne zaman oluşturulacağı hakkında bilgi edinmek için Entity Framework'ün çakışmaları algılayabilmesi gerekir. Bu nedenle, veritabanını ve veri modelini uygun şekilde yapılandırmanız gerekir. Çakışma algılamayı etkinleştirmeye yönelik bazı seçenekler şunlardır:
Veritabanına, bir satırın ne zaman değiştirildiğini belirlemek için kullanılabilecek bir tablo sütunu ekleyin. Daha sonra Entity Framework'i bu sütunu SQL
Update
veyaDelete
komutların yan tümcesineWhere
dahil etmek üzere yapılandırabilirsiniz.Bu, tablodaki sütunun
Timestamp
amacıdırOfficeAssignment
.Sütunun
Timestamp
veri türü olarak da adlandırılırTimestamp
. Ancak sütun aslında bir tarih veya saat değeri içermez. Bunun yerine değer, satır her güncelleştirildiğinde artırılan sıralı bir sayıdır. BirUpdate
veya komutundaWhere
yan tümcesi özgünTimestamp
değeriDelete
içerir. Güncelleştirilmekte olan satır başka bir kullanıcı tarafından değiştirildiyse içindeki değer özgün değerdenTimestamp
farklıdır, bu nedenleWhere
yan tümcesi güncelleştirilecek satır döndürmez. Entity Framework, geçerliUpdate
veyaDelete
komut tarafından güncelleştirilmiş satır olmadığını bulduğunda (yani, etkilenen satırların sayısı sıfır olduğunda), bunu eşzamanlılık çakışması olarak yorumlar.Entity Framework'leri tablodaki
Where
her sütunun özgün değerlerini veDelete
komutlarının yan tümcesineUpdate
dahil etmek için yapılandırın.İlk seçenekte olduğu gibi, satırdaki herhangi bir şey satır ilk okunduktan sonra değiştiyse,
Where
yan tümcesi güncelleştirilecek bir satır döndürmez ve Entity Framework bu satırı eşzamanlılık çakışması olarak yorumlar. Bu yöntem birTimestamp
alan kullanmak kadar etkilidir, ancak verimli olmayabilir. Çok sayıda sütunu olan veritabanı tablolarında çok büyükWhere
yan tümcelere neden olabilir ve bir web uygulamasında büyük miktarlarda durum korumanız gerekebilir. Sunucu kaynakları (örneğin, oturum durumu) gerektirdiğinden veya web sayfasının kendisine (örneğin, görüntüleme durumu) dahil edilmesi gerektiğinden, büyük miktarlarda durumun korunması uygulama performansını etkileyebilir.
Bu öğreticide, izleme özelliği olmayan bir varlık (varlık) ve izleme özelliğine ( Department
varlık) sahip OfficeAssignment
bir varlık için iyimser eşzamanlılık çakışmaları için hata işleme ekleyebilirsiniz.
İzleme Özelliği Olmadan İyimser Eşzamanlılığı İşleme
Varlığın Department
izleme (Timestamp
) özelliği olmayan iyimser eşzamanlılığını uygulamak için aşağıdaki görevleri tamamlayacaksınız:
- Varlıklar için eşzamanlılık izlemeyi etkinleştirmek için
Department
veri modelini değiştirin. SchoolRepository
sınıfında, yöntemindeki eşzamanlılık özel durumlarını işleyebilirSaveChanges
.- Departments.aspx sayfasında, kullanıcıya yapılan değişikliklerin başarısız olduğuna ilişkin bir ileti görüntüleyerek eşzamanlılık özel durumlarını işleyebilirsiniz. Kullanıcı daha sonra geçerli değerleri görebilir ve hala gerekliyse değişiklikleri yeniden deneyebilir.
Veri Modelinde Eşzamanlılık İzlemeyi Etkinleştirme
Visual Studio'da, bu serinin önceki öğreticisinde üzerinde çalıştığınız Contoso University web uygulamasını açın.
SchoolModel.edmx dosyasını açın ve veri modeli tasarımcısında varlıktaki özelliğe sağ tıklayın Name
ve özellikler'e Department
tıklayın. Özellikler penceresinde özelliğini olarak Fixed
değiştirinConcurrencyMode
.
Aynı işlemi diğer birincil anahtar olmayan skaler özellikler (Budget
, StartDate
ve Administrator
.) için de yapın. (Gezinti özellikleri için bunu yapamazsınız.) Bu, Entity Framework veritabanındaki varlığı güncelleştirmek Department
için bir Update
veya Delete
SQL komutu oluşturduğunda, bu sütunların (özgün değerlerle) yan tümcesine Where
eklenmesi gerektiğini belirtir. veya Delete
komutu yürütürken Update
satır bulunamazsa, Entity Framework iyimser-eşzamanlılık özel durumu oluşturur.
Veri modelini kaydedin ve kapatın.
DAL'de Eşzamanlılık Özel Durumlarını İşleme
SchoolRepository.cs dosyasını açın ve ad alanı için System.Data
aşağıdaki using
deyimi ekleyin:
using System.Data;
İyimser eşzamanlılık özel durumlarını işleyen aşağıdaki yeni SaveChanges
yöntemi ekleyin:
public void SaveChanges()
{
try
{
context.SaveChanges();
}
catch (OptimisticConcurrencyException ocex)
{
context.Refresh(RefreshMode.StoreWins, ocex.StateEntries[0].Entity);
throw ocex;
}
}
Bu yöntem çağrıldığında eşzamanlılık hatası oluşursa, bellekteki varlığın özellik değerleri veritabanındaki değerlerle değiştirilir. Web sayfasının işleyebilmesi için eşzamanlılık özel durumu yeniden oluşturulur.
ve yöntemlerindeDeleteDepartment
, yeni yöntemi çağırmak için context.SaveChanges()
var olan çağrısı yerine bir çağrısı SaveChanges()
UpdateDepartment
ekleyin.
Sunu Katmanında Eşzamanlılık Özel Durumlarını İşleme
Departments.aspx dosyasını açın ve denetime DepartmentsObjectDataSource
bir OnDeleted="DepartmentsObjectDataSource_Deleted"
öznitelik ekleyin. Denetimin açma etiketi artık aşağıdaki örneğe benzeyecektir.
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.BLL.SchoolBL" DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartmentsByName" DeleteMethod="DeleteDepartment" UpdateMethod="UpdateDepartment"
ConflictDetection="CompareAllValues" OldValuesParameterFormatString="orig{0}"
OnUpdated="DepartmentsObjectDataSource_Updated" SortParameterName="sortExpression"
OnDeleted="DepartmentsObjectDataSource_Deleted" >
Denetimde DepartmentsGridView
, aşağıdaki örnekte gösterildiği gibi özniteliğindeki DataKeyNames
tüm tablo sütunlarını belirtin. Bunun çok büyük görünüm durumu alanları oluşturacağını unutmayın. Bu, izleme alanı kullanmanın genellikle eşzamanlılık çakışmalarını izlemenin tercih edilen yolu olmasının bir nedenidir.
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource"
DataKeyNames="DepartmentID,Name,Budget,StartDate,Administrator"
OnRowUpdating="DepartmentsGridView_RowUpdating"
OnRowDataBound="DepartmentsGridView_RowDataBound"
AllowSorting="True" >
Departments.aspx.cs dosyasını açın ve ad alanı için System.Data
aşağıdaki using
deyimi ekleyin:
using System.Data;
Eşzamanlılık özel durumlarını işlemek için veri kaynağı denetiminin Updated
ve Deleted
olay işleyicilerinden çağıracağınız aşağıdaki yeni yöntemi ekleyin:
private void CheckForOptimisticConcurrencyException(ObjectDataSourceStatusEventArgs e, string function)
{
if (e.Exception.InnerException is OptimisticConcurrencyException)
{
var concurrencyExceptionValidator = new CustomValidator();
concurrencyExceptionValidator.IsValid = false;
concurrencyExceptionValidator.ErrorMessage =
"The record you attempted to edit or delete was modified by another " +
"user after you got the original value. The edit or delete operation was canceled " +
"and the other user's values have been displayed so you can " +
"determine whether you still want to edit or delete this record.";
Page.Validators.Add(concurrencyExceptionValidator);
e.ExceptionHandled = true;
}
}
Bu kod özel durum türünü denetler ve eşzamanlılık özel durumuysa kod dinamik olarak denetimde ValidationSummary
bir CustomValidator
ileti görüntüleyen bir denetim oluşturur.
Daha önce eklediğiniz olay işleyicisinden Updated
yeni yöntemi çağırın. Ayrıca, aynı yöntemi çağıran (ancak başka bir şey yapmayan) yeni Deleted
bir olay işleyicisi oluşturun:
protected void DepartmentsObjectDataSource_Updated(object sender, ObjectDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
CheckForOptimisticConcurrencyException(e, "update");
// ...
}
}
protected void DepartmentsObjectDataSource_Deleted(object sender, ObjectDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
CheckForOptimisticConcurrencyException(e, "delete");
}
}
Departmanlar Sayfasında İyimser Eşzamanlılığı Test Etme
Departments.aspx sayfasını çalıştırın.
Satırda Düzenle'ye tıklayın ve Bütçe sütunundaki değeri değiştirin. (Mevcut School
veritabanı kayıtları bazı geçersiz veriler içerdiğinden, yalnızca bu öğretici için oluşturduğunuz kayıtları düzenleyebildiğinizi unutmayın. İktisat departmanının kaydı, deney yapmak için güvenli bir kayıttır.)
Yeni bir tarayıcı penceresi açın ve sayfayı yeniden çalıştırın (url'yi ilk tarayıcı penceresinin adres kutusundan ikinci tarayıcı penceresine kopyalayın).
Daha önce düzenlediğiniz satırda Düzenle'ye tıklayın ve Bütçe değerini farklı bir değerle değiştirin.
İkinci tarayıcı penceresinde Güncelleştir'e tıklayın. Bütçe tutarı başarıyla bu yeni değere değiştirildi.
İlk tarayıcı penceresinde Güncelleştir'e tıklayın. Güncelleştirme başarısız oluyor. Bütçe tutarı, ikinci tarayıcı penceresinde ayarladığınız değer kullanılarak yeniden görüntülenir ve bir hata iletisi görürsünüz.
İzleme Özelliği Kullanarak İyimser Eşzamanlılığı İşleme
İzleme özelliğine sahip bir varlığın iyimser eşzamanlılığını işlemek için aşağıdaki görevleri tamamlayacağız:
- Varlıkları yönetmek
OfficeAssignment
için veri modeline saklı yordamlar ekleyin. (İzleme özelliklerinin ve saklı yordamların birlikte kullanılması gerekmez; bunlar çizim için burada birlikte gruplandırılır.) - DAL'de iyimser eşzamanlılık özel durumlarını işlemek için kod da dahil olmak üzere DAL ve varlıklar için
OfficeAssignment
BLL'ye CRUD yöntemleri ekleyin. - Office atamaları web sayfası oluşturun.
- Yeni web sayfasında iyimser eşzamanlılığı test edin.
Veri Modeline OfficeAssignment Saklı Yordamları Ekleme
Model tasarımcısında SchoolModel.edmx dosyasını açın, tasarım yüzeyine sağ tıklayın ve Veritabanından Modeli Güncelleştir'e tıklayın. Veritabanı Nesnelerinizi Seçin iletişim kutusunun Ekle sekmesinde Saklı Yordamlar'ı genişletin ve üç OfficeAssignment
saklı yordamı seçin (aşağıdaki ekran görüntüsüne bakın) ve ardından Son'a tıklayın. (Bu saklı yordamlar, bir betik kullanarak indirdiğinizde veya oluşturduğunuzda veritabanında zaten vardı.)
Varlığa OfficeAssignment
sağ tıklayın ve Saklı Yordam Eşlemesi'ni seçin.
Ekle, Güncelleştir ve Sil işlevlerini ilgili saklı yordamlarını kullanacak şekilde ayarlayın. İşlevin OrigTimestamp
parametresi Update
için Özelliği olarak Timestamp
ayarlayın ve Özgün Değer Kullan seçeneğini belirleyin.
Entity Framework saklı yordamı çağırdığında UpdateOfficeAssignment
parametresindeki OrigTimestamp
sütunun Timestamp
özgün değerini geçirir. Saklı yordam bu parametreyi yan tümcesinde Where
kullanır:
ALTER PROCEDURE [dbo].[UpdateOfficeAssignment]
@InstructorID int,
@Location nvarchar(50),
@OrigTimestamp timestamp
AS
UPDATE OfficeAssignment SET Location=@Location
WHERE InstructorID=@InstructorID AND [Timestamp]=@OrigTimestamp;
IF @@ROWCOUNT > 0
BEGIN
SELECT [Timestamp] FROM OfficeAssignment
WHERE InstructorID=@InstructorID;
END
Saklı yordam ayrıca güncelleştirmeden sonra sütunun Timestamp
yeni değerini seçerek Entity Framework'ün bellekteki varlığı ilgili veritabanı satırıyla eşitlenmiş durumda tutabilmesini OfficeAssignment
sağlar.
(Office atamasını silmeye yönelik saklı yordamın parametresi OrigTimestamp
olmadığını unutmayın. Bu nedenle, Entity Framework bir varlığı silmeden önce değişmediğini doğrulayamaz.)
Veri modelini kaydedin ve kapatın.
DAL'ye OfficeAssignment Yöntemleri Ekleme
ISchoolRepository.cs dosyasını açın ve varlık kümesi için OfficeAssignment
aşağıdaki CRUD yöntemlerini ekleyin:
IEnumerable<OfficeAssignment> GetOfficeAssignments(string sortExpression);
void InsertOfficeAssignment(OfficeAssignment OfficeAssignment);
void DeleteOfficeAssignment(OfficeAssignment OfficeAssignment);
void UpdateOfficeAssignment(OfficeAssignment OfficeAssignment, OfficeAssignment origOfficeAssignment);
SchoolRepository.cs dosyasına aşağıdaki yeni yöntemleri ekleyin. yönteminde UpdateOfficeAssignment
yerine yerel SaveChanges
yöntemini context.SaveChanges
çağırırsınız.
public IEnumerable<OfficeAssignment> GetOfficeAssignments(string sortExpression)
{
return new ObjectQuery<OfficeAssignment>("SELECT VALUE o FROM OfficeAssignments AS o", context).Include("Person").OrderBy("it." + sortExpression).ToList();
}
public void InsertOfficeAssignment(OfficeAssignment officeAssignment)
{
context.OfficeAssignments.AddObject(officeAssignment);
context.SaveChanges();
}
public void DeleteOfficeAssignment(OfficeAssignment officeAssignment)
{
context.OfficeAssignments.Attach(officeAssignment);
context.OfficeAssignments.DeleteObject(officeAssignment);
context.SaveChanges();
}
public void UpdateOfficeAssignment(OfficeAssignment officeAssignment, OfficeAssignment origOfficeAssignment)
{
context.OfficeAssignments.Attach(origOfficeAssignment);
context.ApplyCurrentValues("OfficeAssignments", officeAssignment);
SaveChanges();
}
Test projesinde MockSchoolRepository.cs dosyasını açın ve aşağıdaki OfficeAssignment
koleksiyonu ve CRUD yöntemlerini ekleyin. (Sahte depo, depo arabirimini uygulamalıdır, aksi zaman çözüm derlenmez.)
List<OfficeAssignment> officeAssignments = new List<OfficeAssignment>();
public IEnumerable<OfficeAssignment> GetOfficeAssignments(string sortExpression)
{
return officeAssignments;
}
public void InsertOfficeAssignment(OfficeAssignment officeAssignment)
{
officeAssignments.Add(officeAssignment);
}
public void DeleteOfficeAssignment(OfficeAssignment officeAssignment)
{
officeAssignments.Remove(officeAssignment);
}
public void UpdateOfficeAssignment(OfficeAssignment officeAssignment, OfficeAssignment origOfficeAssignment)
{
officeAssignments.Remove(origOfficeAssignment);
officeAssignments.Add(officeAssignment);
}
BLL'ye OfficeAssignment Yöntemleri Ekleme
Ana projede SchoolBL.cs dosyasını açın ve buna ayarlanan varlık için OfficeAssignment
aşağıdaki CRUD yöntemlerini ekleyin:
public IEnumerable<OfficeAssignment> GetOfficeAssignments(string sortExpression)
{
if (string.IsNullOrEmpty(sortExpression)) sortExpression = "Person.LastName";
return schoolRepository.GetOfficeAssignments(sortExpression);
}
public void InsertOfficeAssignment(OfficeAssignment officeAssignment)
{
try
{
schoolRepository.InsertOfficeAssignment(officeAssignment);
}
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 DeleteOfficeAssignment(OfficeAssignment officeAssignment)
{
try
{
schoolRepository.DeleteOfficeAssignment(officeAssignment);
}
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 UpdateOfficeAssignment(OfficeAssignment officeAssignment, OfficeAssignment origOfficeAssignment)
{
try
{
schoolRepository.UpdateOfficeAssignment(officeAssignment, origOfficeAssignment);
}
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;
}
}
OfficeAssignments Web Sayfası Oluşturma
Site.Master ana sayfasını kullanan yeni bir web sayfası oluşturun ve bunu OfficeAssignments.aspx olarak adlandırın. adlı Content2
denetime aşağıdaki işaretlemeyi Content
ekleyin:
<h2>Office Assignments</h2>
<asp:ObjectDataSource ID="OfficeAssignmentsObjectDataSource" runat="server" TypeName="ContosoUniversity.BLL.SchoolBL"
DataObjectTypeName="ContosoUniversity.DAL.OfficeAssignment" SelectMethod="GetOfficeAssignments"
DeleteMethod="DeleteOfficeAssignment" UpdateMethod="UpdateOfficeAssignment" ConflictDetection="CompareAllValues"
OldValuesParameterFormatString="orig{0}"
SortParameterName="sortExpression" OnUpdated="OfficeAssignmentsObjectDataSource_Updated">
</asp:ObjectDataSource>
<asp:ValidationSummary ID="OfficeAssignmentsValidationSummary" runat="server" ShowSummary="true"
DisplayMode="BulletList" Style="color: Red; width: 40em;" />
<asp:GridView ID="OfficeAssignmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="OfficeAssignmentsObjectDataSource" DataKeyNames="InstructorID,Timestamp"
AllowSorting="True">
<Columns>
<asp:CommandField ShowEditButton="True" ShowDeleteButton="True" ItemStyle-VerticalAlign="Top">
<ItemStyle VerticalAlign="Top"></ItemStyle>
</asp:CommandField>
<asp:TemplateField HeaderText="Instructor" SortExpression="Person.LastName">
<ItemTemplate>
<asp:Label ID="InstructorLastNameLabel" runat="server" Text='<%# Eval("Person.LastName") %>'></asp:Label>,
<asp:Label ID="InstructorFirstNameLabel" runat="server" Text='<%# Eval("Person.FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:DynamicField DataField="Location" HeaderText="Location" SortExpression="Location"/>
</Columns>
<SelectedRowStyle BackColor="LightGray"></SelectedRowStyle>
</asp:GridView>
özniteliğinde DataKeyNames
işaretleme özelliğinin yanı sıra kayıt anahtarını (InstructorID
) da belirttiğine Timestamp
dikkat edin. Öznitelikte özelliklerin DataKeyNames
belirtilmesi, özgün değerlerin geri gönderme işlemi sırasında kullanılabilir olması için denetimin bunları denetim durumuna (görüntüleme durumuna benzer) kaydetmesine neden olur.
Değeri kaydetmediysenizTimestamp
, Entity Framework'ün SQL Update
komutunun Where
yan tümcesi için bu değere sahip olmaması gerekir. Sonuç olarak, güncelleştirilecek hiçbir şey bulunamadı. Sonuç olarak Entity Framework, bir varlık her güncelleştirildiğinde iyimser bir OfficeAssignment
eşzamanlılık özel durumu oluşturur.
OfficeAssignments.aspx.cs dosyasını açın ve veri erişim katmanı için aşağıdaki using
deyimi ekleyin:
using ContosoUniversity.DAL;
Dinamik Veri işlevselliğini etkinleştiren aşağıdaki Page_Init
yöntemi ekleyin. Eşzamanlılık hatalarını denetlemek için denetimin ObjectDataSource
Updated
olayı için aşağıdaki işleyiciyi de ekleyin:
protected void Page_Init(object sender, EventArgs e)
{
OfficeAssignmentsGridView.EnableDynamicData(typeof(OfficeAssignment));
}
protected void OfficeAssignmentsObjectDataSource_Updated(object sender, ObjectDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
var concurrencyExceptionValidator = new CustomValidator();
concurrencyExceptionValidator.IsValid = false;
concurrencyExceptionValidator.ErrorMessage = "The record you attempted to " +
"update has been modified by another user since you last visited this page. " +
"Your update was canceled to allow you to review the other user's " +
"changes and determine if you still want to update this record.";
Page.Validators.Add(concurrencyExceptionValidator);
e.ExceptionHandled = true;
}
}
OfficeAssignments Sayfasında İyimser Eşzamanlılığı Test Etme
OfficeAssignments.aspx sayfasını çalıştırın.
Satırda Düzenle'ye tıklayın ve Konum sütunundaki değeri değiştirin.
Yeni bir tarayıcı penceresi açın ve sayfayı yeniden çalıştırın (url'yi ilk tarayıcı penceresinden ikinci tarayıcı penceresine kopyalayın).
Daha önce düzenlediğiniz satırda Düzenle'ye tıklayın ve Konum değerini farklı bir değerle değiştirin.
İkinci tarayıcı penceresinde Güncelleştir'e tıklayın.
İlk tarayıcı penceresine geçin ve Güncelleştir'e tıklayın.
Bir hata iletisi görürsünüz ve Konum değeri, ikinci tarayıcı penceresinde değiştirdiğiniz değeri gösterecek şekilde güncelleştirildi.
EntityDataSource Denetimi ile Eşzamanlılığı İşleme
Denetim, EntityDataSource
veri modelindeki eşzamanlılık ayarlarını tanıyan ve güncelleştirme ve silme işlemlerini uygun şekilde işleyen yerleşik mantık içerir. Ancak, tüm özel durumlarda olduğu gibi, kullanıcı dostu bir hata iletisi sağlamak için özel durumları kendiniz işlemeniz OptimisticConcurrencyException
gerekir.
Ardından, güncelleştirme ve silme işlemlerine izin vermek ve eşzamanlılık çakışması oluşursa hata iletisi görüntülemek için Courses.aspx sayfasını (denetim kullanan EntityDataSource
) yapılandıracaksınız. Varlığın Course
eşzamanlılık izleme sütunu yoktur, bu nedenle varlıkla Department
yaptığınız yöntemi kullanırsınız: anahtar olmayan tüm özelliklerin değerlerini izleme.
SchoolModel.edmx dosyasını açın. Varlığın (Title
, Credits
ve DepartmentID
) anahtar olmayan özellikleri Course
için Eşzamanlılık Modu özelliğini olarak Fixed
ayarlayın. Ardından veri modelini kaydedip kapatın.
Courses.aspx sayfasını açın ve aşağıdaki değişiklikleri yapın:
Denetimde
CoursesEntityDataSource
veEnableDelete="true"
öznitelikleri ekleyinEnableUpdate="true"
. Bu denetimin açma etiketi artık aşağıdaki örneğe benzer:<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="false" AutoGenerateWhereClause="True" EntitySetName="Courses" EnableUpdate="true" EnableDelete="true">
Denetimde
CoursesGridView
öznitelik değerini olarak"CourseID,Title,Credits,DepartmentID"
değiştirinDataKeyNames
. Ardından öğeyeColumns
Düzenle ve Sil düğmelerini ()<asp:CommandField ShowEditButton="True" ShowDeleteButton="True" />
gösteren birCommandField
öğe ekleyin. DenetimGridView
artık aşağıdaki örneğe benzer:<asp:GridView ID="CoursesGridView" runat="server" AutoGenerateColumns="False" DataKeyNames="CourseID,Title,Credits,DepartmentID" DataSourceID="CoursesEntityDataSource" > <Columns> <asp:CommandField ShowEditButton="True" ShowDeleteButton="True" /> <asp:BoundField DataField="CourseID" HeaderText="CourseID" ReadOnly="True" SortExpression="CourseID" /> <asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" /> <asp:BoundField DataField="Credits" HeaderText="Credits" SortExpression="Credits" /> </Columns> </asp:GridView>
Sayfayı çalıştırın ve Departmanlar sayfasında daha önce yaptığınız gibi bir çakışma durumu oluşturun. Sayfayı iki tarayıcı penceresinde çalıştırın, her pencerede aynı satırda Düzenle'ye tıklayın ve her birinde farklı bir değişiklik yapın. Bir pencerede Güncelleştir'e tıklayın ve ardından diğer pencerede Güncelleştir'e tıklayın. İkinci kez Güncelleştir'e tıkladığınızda, işlenmeyen bir eşzamanlılık özel durumunun neden olduğu hata sayfasını görürsünüz.
Bu hatayı, denetim için ObjectDataSource
nasıl işlediğinize çok benzer bir şekilde işlersiniz. Courses.aspx sayfasını açın ve denetimde CoursesEntityDataSource
ve Updated
olayları için Deleted
işleyicileri belirtin. Denetimin açma etiketi artık aşağıdaki örneğe benzer:
<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="false"
AutoGenerateWhereClause="true" EntitySetName="Courses"
EnableUpdate="true" EnableDelete="true"
OnDeleted="CoursesEntityDataSource_Deleted"
OnUpdated="CoursesEntityDataSource_Updated">
Denetimden CoursesGridView
önce aşağıdaki ValidationSummary
denetimi ekleyin:
<asp:ValidationSummary ID="CoursesValidationSummary" runat="server"
ShowSummary="true" DisplayMode="BulletList" />
Courses.aspx.cs dosyasında ad alanı için System.Data
bir using
deyim ekleyin, eşzamanlılık özel durumlarını denetleyan bir yöntem ekleyin ve denetimin EntityDataSource
Updated
ve Deleted
işleyicilerinin işleyicilerini ekleyin. Kod aşağıdaki gibi görünür:
using System.Data;
protected void CoursesEntityDataSource_Updated(object sender, EntityDataSourceChangedEventArgs e)
{
CheckForOptimisticConcurrencyException(e, "update");
}
protected void CoursesEntityDataSource_Deleted(object sender, EntityDataSourceChangedEventArgs e)
{
CheckForOptimisticConcurrencyException(e, "delete");
}
private void CheckForOptimisticConcurrencyException(EntityDataSourceChangedEventArgs e, string function)
{
if (e.Exception != null && e.Exception is OptimisticConcurrencyException)
{
var concurrencyExceptionValidator = new CustomValidator();
concurrencyExceptionValidator.IsValid = false;
concurrencyExceptionValidator.ErrorMessage =
"The record you attempted to edit or delete was modified by another " +
"user after you got the original value. The edit or delete operation was canceled " +
"and the other user's values have been displayed so you can " +
"determine whether you still want to edit or delete this record.";
Page.Validators.Add(concurrencyExceptionValidator);
e.ExceptionHandled = true;
}
}
Bu kodla denetim için ObjectDataSource
yaptıklarınız arasındaki tek fark, bu durumda eşzamanlılık özel durumunun bu özel InnerException
durumun özelliği yerine olay bağımsız değişkenleri nesnesinin özelliğinde olmasıdırException
.
Sayfayı çalıştırın ve yeniden eşzamanlılık çakışması oluşturun. Bu kez bir hata iletisi görürsünüz:
Bu, eşzamanlılık çakışmalarını işlemeye giriş işlemini tamamlar. Sonraki öğretici, Entity Framework kullanan bir web uygulamasında performansın nasıl geliştirileceğine ilişkin rehberlik sağlayacaktır.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin