Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
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 mempelajari cara mengurutkan dan memfilter data menggunakan ObjectDataSource
kontrol dan Kerangka Kerja Entitas. Tutorial ini menunjukkan opsi untuk menangani konkurensi dalam aplikasi web ASP.NET yang menggunakan Kerangka Kerja Entitas. Anda akan membuat halaman web baru yang didedikasikan untuk memperbarui penugasan kantor instruktur. Anda akan menangani masalah konkurensi di halaman tersebut dan di halaman Departemen yang Anda buat sebelumnya.
Konflik Konkurensi
Konflik konkurensi terjadi ketika satu pengguna mengedit rekaman dan pengguna lain mengedit rekaman yang sama sebelum perubahan pengguna pertama ditulis ke database. Jika Anda tidak menyiapkan Kerangka Kerja Entitas untuk mendeteksi konflik tersebut, siapa pun yang memperbarui database terakhir kali menimpa perubahan pengguna lain. Dalam banyak aplikasi, risiko ini dapat diterima, dan Anda tidak perlu mengonfigurasi aplikasi untuk menangani kemungkinan konflik konkurensi. (Jika ada beberapa pengguna, atau beberapa pembaruan, atau jika tidak terlalu penting jika beberapa perubahan ditimpa, biaya pemrograman untuk konkurensi mungkin melebihi manfaatnya.) Jika Anda tidak perlu khawatir tentang konflik konkurensi, Anda dapat melewati tutorial ini; dua tutorial yang tersisa dalam seri tidak bergantung pada apa pun yang Anda bangun dalam yang satu ini.
Konkurensi Pesimis (Penguncian)
Jika aplikasi Anda memang perlu mencegah kehilangan data yang tidak disengaja dalam skenario konkurensi, salah satu cara untuk melakukannya adalah dengan menggunakan kunci database. Ini disebut konkurensi pesimis. Misalnya, sebelum Membaca baris dari database, Anda meminta kunci untuk akses baca-saja atau untuk pembaruan. Jika Anda mengunci baris untuk akses pembaruan, tidak ada pengguna lain yang diizinkan untuk mengunci baris baik untuk akses baca-saja atau perbarui, karena mereka akan mendapatkan salinan data yang sedang dalam proses diubah. Jika Anda mengunci baris untuk akses baca-saja, orang lain juga dapat menguncinya untuk akses baca-saja tetapi tidak untuk pembaruan.
Mengelola kunci memiliki beberapa kelemahan. Ini bisa rumit untuk diprogram. Ini membutuhkan sumber daya manajemen database yang signifikan, dan dapat menyebabkan masalah performa saat jumlah pengguna aplikasi meningkat (artinya, itu tidak menskalakan dengan baik). Untuk alasan ini, tidak semua sistem manajemen database mendukung konkurensi pesimis. Kerangka Kerja Entitas tidak menyediakan dukungan bawaan untuk itu, dan tutorial ini tidak menunjukkan kepada Anda cara mengimplementasikannya.
Konkurensi optimis
Alternatif untuk konkurensi pesimis adalah konkurensi optimis. Konkurensi optimis berarti memungkinkan konflik konkurensi terjadi, dan kemudian bereaksi dengan tepat jika terjadi. Misalnya, John menjalankan halaman Department.aspx , mengklik tautan Edit untuk departemen Riwayat, dan mengurangi jumlah Anggaran dari $1.000.000,00 menjadi $125.000,00. (John mengelola departemen yang bersaing dan ingin membebaskan uang untuk departemennya sendiri.)
Sebelum John mengklik Perbarui, Jane menjalankan halaman yang sama, mengklik tautan Edit untuk departemen Riwayat, lalu mengubah bidang Tanggal Mulai dari 10/10/2011 menjadi 1/1/1999. (Jane mengelola departemen Sejarah dan ingin memberikannya lebih senioritas.)
John mengklik Perbarui terlebih dahulu, lalu Jane mengklik Perbarui. Browser Jane sekarang mencantumkan jumlah Anggaran sebesar $1.000.000,00, tetapi ini salah karena jumlahnya telah diubah oleh John menjadi $125.000,00.
Beberapa tindakan yang dapat Anda lakukan dalam skenario ini meliputi yang berikut ini:
Anda dapat melacak properti mana yang telah dimodifikasi pengguna dan hanya memperbarui kolom terkait dalam database. Dalam skenario contoh, tidak ada data yang akan hilang, karena properti yang berbeda diperbarui oleh dua pengguna. Lain kali seseorang menelusuri departemen Sejarah, mereka akan melihat 1/1/1999 dan $ 125.000,00.
Ini adalah perilaku default dalam Kerangka Kerja Entitas, dan dapat secara substansial mengurangi jumlah konflik yang dapat mengakibatkan kehilangan data. Namun, perilaku ini tidak menghindari kehilangan data jika perubahan yang bersaing dilakukan pada properti entitas yang sama. Selain itu, perilaku ini tidak selalu dimungkinkan; saat Anda memetakan prosedur tersimpan ke jenis entitas, semua properti entitas diperbarui ketika ada perubahan pada entitas yang dibuat dalam database.
Kau bisa membiarkan perubahan Jane menimpa perubahan John. Setelah Jane mengklik Perbarui, jumlah Anggaran kembali ke $1.000.000,00. Ini disebut skenario Client Wins atau Last in Wins . (Nilai klien lebih diutamakan daripada apa yang ada di penyimpanan data.)
Anda dapat mencegah perubahan Jane diperbarui dalam database. Biasanya, Anda akan menampilkan pesan kesalahan, menunjukkan status data saat ini, dan memungkinkannya untuk masuk kembali perubahannya jika dia masih ingin membuatnya. Anda dapat mengotomatiskan proses lebih lanjut dengan menyimpan masukannya dan memberinya kesempatan untuk menerapkannya kembali tanpa harus memasukkannya kembali. Ini disebut skenario Store Wins . (Nilai penyimpanan data lebih diutamakan daripada nilai yang dikirimkan oleh klien.)
Mendeteksi Konflik Konkurensi
Dalam Kerangka Kerja Entitas, Anda dapat mengatasi konflik dengan menangani OptimisticConcurrencyException
pengecualian yang dilemparkan Kerangka Kerja Entitas. Untuk mengetahui kapan harus melemparkan pengecualian ini, Kerangka Kerja Entitas harus dapat mendeteksi konflik. Oleh karena itu, Anda harus mengonfigurasi database dan model data dengan tepat. Beberapa opsi untuk mengaktifkan deteksi konflik meliputi yang berikut ini:
Dalam database, sertakan kolom tabel yang bisa digunakan untuk menentukan kapan baris telah diubah. Anda kemudian dapat mengonfigurasi Kerangka Kerja Entitas untuk menyertakan kolom tersebut
Where
dalam klausa SQLUpdate
atauDelete
perintah.Itulah tujuan
Timestamp
kolom dalamOfficeAssignment
tabel.Jenis
Timestamp
data kolom juga disebutTimestamp
. Namun, kolom sebenarnya tidak berisi nilai tanggal atau waktu. Sebaliknya, nilainya adalah angka berurutan yang bertahap setiap kali baris diperbarui.Update
Dalam perintah atauDelete
,Where
klausul menyertakan nilai asliTimestamp
. Jika baris yang diperbarui telah diubah oleh pengguna lain, nilai di berbeda dari nilai asli, sehinggaWhere
klausa tidak mengembalikan baris untuk diperbaruiTimestamp
. Ketika Kerangka Kerja Entitas menemukan bahwa tidak ada baris yang telah diperbarui oleh saat iniUpdate
atauDelete
perintah (yaitu, ketika jumlah baris yang terpengaruh adalah nol), itu menafsirkan bahwa sebagai konflik konkurensi.Konfigurasikan Kerangka Kerja Entitas untuk menyertakan nilai asli setiap kolom dalam tabel dalam
Where
klausulUpdate
danDelete
perintah.Seperti pada opsi pertama, jika ada sesuatu di baris yang telah berubah sejak baris pertama kali dibaca,
Where
klausa tidak akan mengembalikan baris untuk diperbarui, yang ditafsirkan oleh Kerangka Kerja Entitas sebagai konflik konkurensi. Metode ini seefektif menggunakanTimestamp
bidang, tetapi bisa tidak efisien. Untuk tabel database yang memiliki banyak kolom, tabel dapat menghasilkan klausa yang sangat besarWhere
, dan dalam aplikasi web, tabel dapat mengharuskan Anda mempertahankan status dalam jumlah besar. Mempertahankan status dalam jumlah besar dapat memengaruhi performa aplikasi karena memerlukan sumber daya server (misalnya, status sesi) atau harus disertakan dalam halaman web itu sendiri (misalnya, status tampilan).
Dalam tutorial ini Anda akan menambahkan penanganan kesalahan untuk konflik konkurensi optimis untuk entitas yang tidak memiliki properti pelacakan ( Department
entitas) dan untuk entitas yang memang memiliki properti pelacakan ( OfficeAssignment
entitas).
Menangani Konkurensi Optimis Tanpa Properti Pelacakan
Untuk menerapkan konkurensi optimis untuk Department
entitas, yang tidak memiliki properti pelacakan (Timestamp
), Anda akan menyelesaikan tugas-tugas berikut:
- Ubah model data untuk mengaktifkan pelacakan konkurensi untuk
Department
entitas. -
SchoolRepository
Di kelas , tangani pengecualian konkurensi dalamSaveChanges
metode . - Di halaman Departments.aspx , tangani pengecualian konkurensi dengan menampilkan pesan kepada pengguna yang memperingatkan bahwa perubahan yang dicoba tidak berhasil. Pengguna kemudian dapat melihat nilai saat ini dan mencoba kembali perubahan jika masih diperlukan.
Mengaktifkan Pelacakan Konkurensi dalam Model Data
Di Visual Studio, buka aplikasi web Contoso University yang sedang Anda kerjakan di tutorial sebelumnya dalam seri ini.
Buka SchoolModel.edmx, dan di perancang model data, klik Name
kanan properti di Department
entitas lalu klik Properti. Di jendela Properti , ubah properti menjadi ConcurrencyMode
Fixed
.
Lakukan hal yang sama untuk properti skalar non-kunci primer lainnya (Budget
, , StartDate
dan Administrator
.) (Anda tidak dapat melakukan ini untuk properti navigasi.) Ini menentukan bahwa setiap kali Kerangka Kerja Entitas menghasilkan Update
perintah atau Delete
SQL untuk memperbarui Department
entitas dalam database, kolom ini (dengan nilai asli) harus disertakan dalam Where
klausul. Jika tidak ada baris yang ditemukan saat Update
perintah atau Delete
dijalankan, Kerangka Kerja Entitas akan memberikan pengecualian konkurensi optimis.
Simpan dan tutup model data.
Menangani Pengecualian Konkurensi dalam DAL
Buka SchoolRepository.cs dan tambahkan pernyataan berikut using
untuk System.Data
namespace:
using System.Data;
Tambahkan metode baru SaveChanges
berikut, yang menangani pengecualian konkurensi optimis:
public void SaveChanges()
{
try
{
context.SaveChanges();
}
catch (OptimisticConcurrencyException ocex)
{
context.Refresh(RefreshMode.StoreWins, ocex.StateEntries[0].Entity);
throw ocex;
}
}
Jika kesalahan konkurensi terjadi ketika metode ini dipanggil, nilai properti entitas dalam memori diganti dengan nilai yang saat ini ada di database. Pengecualian konkurensi ditumbuhi kembali sehingga halaman web dapat menanganinya.
DeleteDepartment
Dalam metode dan UpdateDepartment
, ganti panggilan yang ada ke context.SaveChanges()
dengan panggilan ke SaveChanges()
untuk memanggil metode baru.
Menangani Pengecualian Konkurensi di Lapisan Presentasi
Buka Departments.aspx dan tambahkan OnDeleted="DepartmentsObjectDataSource_Deleted"
atribut ke DepartmentsObjectDataSource
kontrol. Tag pembuka untuk kontrol sekarang akan menyerupai contoh berikut.
<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" >
DepartmentsGridView
Dalam kontrol, tentukan semua kolom tabel dalam DataKeyNames
atribut , seperti yang ditunjukkan dalam contoh berikut. Perhatikan bahwa ini akan membuat bidang status tampilan yang sangat besar, yang merupakan salah satu alasan mengapa menggunakan bidang pelacakan umumnya adalah cara yang disukai untuk melacak konflik konkurensi.
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource"
DataKeyNames="DepartmentID,Name,Budget,StartDate,Administrator"
OnRowUpdating="DepartmentsGridView_RowUpdating"
OnRowDataBound="DepartmentsGridView_RowDataBound"
AllowSorting="True" >
Buka Departments.aspx.cs dan tambahkan pernyataan berikut using
untuk System.Data
namespace:
using System.Data;
Tambahkan metode baru berikut, yang akan Anda panggil dari kontrol Updated
sumber data dan Deleted
penanganan aktivitas untuk menangani pengecualian konkurensi:
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;
}
}
Kode ini memeriksa jenis pengecualian, dan jika itu adalah pengecualian konkurensi, kode secara dinamis membuat CustomValidator
kontrol yang pada gilirannya menampilkan pesan dalam ValidationSummary
kontrol.
Panggil metode baru dari penanganan Updated
aktivitas yang Anda tambahkan sebelumnya. Selain itu, buat penanganan aktivitas baru Deleted
yang memanggil metode yang sama (tetapi tidak melakukan hal lain):
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");
}
}
Menguji Konkurensi Optimis di Halaman Departemen
Jalankan halaman Departments.aspx .
Klik Edit dalam baris dan ubah nilai di kolom Anggaran . (Ingat bahwa Anda hanya bisa mengedit rekaman yang telah Anda buat untuk tutorial ini, karena rekaman database yang ada School
berisi beberapa data yang tidak valid. Catatan untuk departemen Ekonomi adalah catatan yang aman untuk dieksperimen.)
Buka jendela browser baru dan jalankan halaman lagi (salin URL dari kotak alamat jendela browser pertama ke jendela browser kedua).
Klik Edit di baris yang sama dengan yang Anda edit sebelumnya dan ubah nilai Anggaran menjadi sesuatu yang berbeda.
Di jendela browser kedua, klik Perbarui. Jumlah Anggaran berhasil diubah ke nilai baru ini.
Di jendela browser pertama, klik Perbarui. Pembaruan gagal. Jumlah Anggaran diputar ulang menggunakan nilai yang Anda tetapkan di jendela browser kedua, dan Anda melihat pesan kesalahan.
Menangani Konkurensi Optimis Menggunakan Properti Pelacakan
Untuk menangani konkurensi optimis untuk entitas yang memiliki properti pelacakan, Anda akan menyelesaikan tugas berikut:
- Tambahkan prosedur tersimpan ke model data untuk mengelola
OfficeAssignment
entitas. (Properti pelacakan dan prosedur tersimpan tidak harus digunakan bersama-sama; properti tersebut hanya dikelompokkan bersama di sini untuk ilustrasi.) - Tambahkan metode CRUD ke DAL dan BLL untuk
OfficeAssignment
entitas, termasuk kode untuk menangani pengecualian konkurensi optimis dalam DAL. - Buat halaman web penugasan kantor.
- Uji konkurensi optimis di halaman web baru.
Menambahkan Prosedur Tersimpan OfficeAssignment ke Model Data
Buka file SchoolModel.edmx di perancang model, klik kanan permukaan desain, dan klik Perbarui Model dari Database. Di tab Tambahkan dari kotak dialog Pilih Objek Database Anda , perluas Prosedur Tersimpan dan pilih tiga OfficeAssignment
prosedur tersimpan (lihat cuplikan layar berikut), lalu klik Selesai. (Prosedur tersimpan ini sudah ada di database saat Anda mengunduh atau membuatnya menggunakan skrip.)
OfficeAssignment
Klik kanan entitas dan pilih Pemetaan Prosedur Tersimpan.
Atur fungsi Sisipkan, Perbarui, dan Hapus untuk menggunakan prosedur tersimpan terkait.
OrigTimestamp
Untuk parameter Update
fungsi, atur Properti ke Timestamp
dan pilih opsi Gunakan Nilai Asli.
Ketika Entity Framework memanggil UpdateOfficeAssignment
prosedur tersimpan Timestamp
, itu akan meneruskan nilai asli kolom dalam OrigTimestamp
parameter . Prosedur tersimpan menggunakan parameter ini dalam klausulnya Where
:
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
Prosedur tersimpan Timestamp
juga memilih nilai baru kolom setelah pembaruan sehingga Kerangka Kerja Entitas dapat menjaga OfficeAssignment
entitas yang berada dalam memori tetap sinkron dengan baris database yang sesuai.
(Perhatikan bahwa prosedur tersimpan untuk menghapus penetapan office tidak memiliki OrigTimestamp
parameter. Karena itu, Kerangka Kerja Entitas tidak dapat memverifikasi bahwa entitas tidak berubah sebelum menghapusnya.)
Simpan dan tutup model data.
Menambahkan Metode OfficeAssignment ke DAL
Buka ISchoolRepository.cs dan tambahkan metode CRUD berikut untuk OfficeAssignment
kumpulan entitas:
IEnumerable<OfficeAssignment> GetOfficeAssignments(string sortExpression);
void InsertOfficeAssignment(OfficeAssignment OfficeAssignment);
void DeleteOfficeAssignment(OfficeAssignment OfficeAssignment);
void UpdateOfficeAssignment(OfficeAssignment OfficeAssignment, OfficeAssignment origOfficeAssignment);
Tambahkan metode baru berikut ke SchoolRepository.cs. Dalam metode , UpdateOfficeAssignment
Anda memanggil metode lokal SaveChanges
alih-alih context.SaveChanges
.
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();
}
Dalam proyek pengujian, buka MockSchoolRepository.cs dan tambahkan koleksi dan metode CRUD berikut OfficeAssignment
ke dalamnya. (Repositori tiruan harus mengimplementasikan antarmuka repositori, atau solusinya tidak akan dikompilasi.)
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);
}
Menambahkan Metode OfficeAssignment ke BLL
Dalam proyek utama, buka SchoolBL.cs dan tambahkan metode CRUD berikut untuk entitas yang OfficeAssignment
diatur ke dalamnya:
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;
}
}
Membuat Halaman Web OfficeAssignments
Buat halaman web baru yang menggunakan halaman master Site.Master dan beri nama OfficeAssignments.aspx. Tambahkan markup berikut ke Content
kontrol bernama Content2
:
<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>
Perhatikan bahwa dalam DataKeyNames
atribut , markup menentukan Timestamp
properti serta kunci rekaman (InstructorID
). Menentukan properti dalam DataKeyNames
atribut menyebabkan kontrol menyimpannya dalam status kontrol (yang mirip dengan status tampilan) sehingga nilai asli tersedia selama pemrosesan postback.
Jika Anda tidak menyimpan Timestamp
nilai, Kerangka Kerja Entitas tidak akan memilikinya untuk Where
klausa perintah SQL Update
. Akibatnya tidak ada yang akan ditemukan untuk diperbarui. Akibatnya, Kerangka Kerja Entitas akan memberikan pengecualian konkurensi optimis setiap kali OfficeAssignment
entitas diperbarui.
Buka OfficeAssignments.aspx.cs dan tambahkan pernyataan berikut using
untuk lapisan akses data:
using ContosoUniversity.DAL;
Tambahkan metode berikut Page_Init
, yang memungkinkan fungsionalitas Data Dinamis. Tambahkan juga handler berikut untuk ObjectDataSource
peristiwa kontrol Updated
untuk memeriksa kesalahan konkurensi:
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;
}
}
Menguji Konkurensi Optimis di Halaman OfficeAssignments
Jalankan halaman OfficeAssignments.aspx .
Klik Edit dalam baris dan ubah nilai di kolom Lokasi .
Buka jendela browser baru dan jalankan halaman lagi (salin URL dari jendela browser pertama ke jendela browser kedua).
Klik Edit di baris yang sama dengan yang Anda edit sebelumnya dan ubah nilai Lokasi menjadi sesuatu yang berbeda.
Di jendela browser kedua, klik Perbarui.
Beralih ke jendela browser pertama dan klik Perbarui.
Anda melihat pesan kesalahan dan nilai Lokasi telah diperbarui untuk memperlihatkan nilai yang Anda ubah di jendela browser kedua.
Menangani Konkurensi dengan Kontrol EntityDataSource
Kontrol EntityDataSource
ini mencakup logika bawaan yang mengenali pengaturan konkurensi dalam model data dan menangani operasi pembaruan dan penghapusan yang sesuai. Namun, seperti semua pengecualian, Anda harus menangani OptimisticConcurrencyException
pengecualian sendiri untuk memberikan pesan kesalahan yang mudah digunakan.
Selanjutnya, Anda akan mengonfigurasi halaman Courses.aspx (yang menggunakan EntityDataSource
kontrol) untuk memungkinkan operasi pembaruan dan penghapusan dan untuk menampilkan pesan kesalahan jika konflik konkurensi terjadi. Entitas Course
tidak memiliki kolom pelacakan konkurensi, sehingga Anda akan menggunakan metode yang sama dengan Department
entitas: lacak nilai semua properti non-kunci.
Buka file SchoolModel.edmx . Untuk properti Course
non-kunci entitas (Title
, Credits
, dan DepartmentID
), atur properti Mode Konkurensi ke Fixed
. Kemudian simpan dan tutup model data.
Buka halaman Courses.aspx dan buat perubahan berikut:
CoursesEntityDataSource
Dalam kontrol, tambahkanEnableUpdate="true"
atribut danEnableDelete="true"
. Tag pembuka untuk kontrol tersebut sekarang menyerupai contoh berikut:<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="false" AutoGenerateWhereClause="True" EntitySetName="Courses" EnableUpdate="true" EnableDelete="true">
CoursesGridView
Dalam kontrol, ubah nilai atribut menjadiDataKeyNames
"CourseID,Title,Credits,DepartmentID"
. Lalu tambahkanCommandField
elemen keColumns
elemen yang memperlihatkan tombol Edit dan Hapus (<asp:CommandField ShowEditButton="True" ShowDeleteButton="True" />
).GridView
Kontrol sekarang menyerupai contoh berikut:<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>
Jalankan halaman dan buat situasi konflik seperti yang Anda lakukan sebelumnya di halaman Departemen. Jalankan halaman di dua jendela browser, klik Edit di baris yang sama di setiap jendela, dan buat perubahan yang berbeda di masing-masing jendela. Klik Perbarui dalam satu jendela lalu klik Perbarui di jendela lain. Saat Anda mengklik Perbarui kedua kalinya, Anda akan melihat halaman kesalahan yang dihasilkan dari pengecualian konkurensi yang tidak tertangani.
Anda menangani kesalahan ini dengan cara yang sangat mirip dengan cara Anda menanganinya untuk ObjectDataSource
kontrol. Buka halaman Courses.aspx , dan di CoursesEntityDataSource
kontrol, tentukan handler untuk Deleted
peristiwa dan Updated
. Tag pembuka kontrol sekarang menyerupai contoh berikut:
<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">
CoursesGridView
Sebelum kontrol, tambahkan kontrol berikutValidationSummary
:
<asp:ValidationSummary ID="CoursesValidationSummary" runat="server"
ShowSummary="true" DisplayMode="BulletList" />
Di Courses.aspx.cs, tambahkan using
pernyataan untuk System.Data
namespace, tambahkan metode yang memeriksa pengecualian konkurensi, dan tambahkan handler untuk EntityDataSource
kontrol Updated
dan Deleted
handler. Kode akan terlihat seperti berikut:
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;
}
}
Satu-satunya perbedaan antara kode ini dan apa yang Anda lakukan untuk ObjectDataSource
kontrol adalah bahwa dalam hal ini pengecualian konkurensi ada di Exception
properti objek argumen peristiwa daripada di properti pengecualian tersebut InnerException
.
Jalankan halaman dan buat konflik konkurensi lagi. Kali ini Anda melihat pesan kesalahan:
Ini menyelesaikan pengenalan penanganan konflik konkurensi. Tutorial berikutnya akan memberikan panduan tentang cara meningkatkan performa dalam aplikasi web yang menggunakan Kerangka Kerja Entitas.