Aracılığıyla paylaş


ASP.NET MVC Uygulamasında Entity Framework ile Eşzamanlılığı İşleme (7/10)

tarafından Tom Dykstra

Contoso University örnek web uygulaması, Entity Framework 5 Code First ve Visual Studio 2012 kullanarak ASP.NET MVC 4 uygulamalarının nasıl oluşturulacağını gösterir. Öğretici serisi hakkında bilgi için serideki ilk öğreticiye bakın.

Not

Çözemediğiniz bir sorunla karşılaşırsanız tamamlanmış bölümü indirin ve sorununuzu yeniden oluşturmayı deneyin. Kodunuzu tamamlanmış kodla karşılaştırarak sorunun çözümünü genel olarak bulabilirsiniz. Bazı yaygın hatalar ve bunların nasıl çözüldüğü için bkz . Hatalar ve Geçici Çözümler.

Önceki iki öğreticide ilgili verilerle çalıştınız. Bu öğreticide eşzamanlılığın nasıl işleneceğini gösterilmektedir. Varlıkla Department çalışan web sayfaları oluşturacaksınız ve varlıkları düzenleyen ve silecek Department sayfalar eşzamanlılık hatalarını işler. Aşağıdaki çizimlerde, eşzamanlılık çakışması oluşursa görüntülenen bazı iletiler de dahil olmak üzere Dizin ve Sil sayfaları gösterilmektedir.

Düzenlemelerden önce Contoso Üniversite Bölümleri sayfasını gösteren ekran görüntüsü.

Ekran görüntüsü, değeri başka bir kullanıcı tarafından değiştirildiği için işlemin iptal edildiğini açıklayan bir iletinin yer aldığı Üniversite sayfasını gösterir.

Eşzamanlılık Çakışmaları

Eşzamanlılık çakışması, bir kullanıcının düzenlemek için bir varlığın verilerini görüntülemesi ve ardından başka bir kullanıcı, ilk kullanıcının değişikliği veritabanına yazılmadan önce aynı varlığın verilerini güncelleştirdiğinde oluşur. Bu tür çakışmaların algılanması etkinleştirilmezse, veritabanını güncelleştiren kişi son olarak diğer kullanıcının değişikliklerinin üzerine yazar. Birçok uygulamada bu risk kabul edilebilir bir risktir: Az sayıda kullanıcı veya birkaç güncelleştirme varsa veya bazı değişikliklerin üzerine yazılırsa gerçekten kritik değilse eşzamanlılık programlama maliyeti avantajdan daha ağır basabilir. Bu durumda, eşzamanlılık çakışmalarını işlemek için uygulamayı yapılandırmanız gerekmez.

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, değiştirme sürecinde olan verilerin bir kopyasını alacakları için, başka hiçbir kullanıcının satırı salt okunur veya güncelleştirme erişimi için kilitlemesine izin verilmez. 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 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, bu çerçeve 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 Departman düzenleme sayfasını çalıştırır, İngilizce bölümü için Bütçe tutarını 350.000,00 TL'den 0,00 TL'ye değiştirir.

Changing_English_dept_budget_to_100000

John Kaydet'e tıklamadan önce, Jane aynı sayfayı çalıştırır ve Başlangıç Tarihi alanını 1/9/2007'den 8/8/2013'e değiştirir.

Changing_English_dept_start_date_to_1999

John önce Kaydet'e tıklar ve tarayıcı Dizin sayfasına döndüğünde değişikliğini görür, ardından Jane Kaydet'e tıklar. Bundan sonra ne olacağı eşzamanlılık çakışmalarını nasıl işlediğinize göre belirlenir. Seçeneklerden bazıları şunlardır:

  • Kullanıcının hangi özelliği değiştirdiğini izleyebilir ve yalnızca veritabanındaki ilgili sütunları güncelleştirebilirsiniz. Örnek senaryoda, iki kullanıcı tarafından farklı özellikler güncelleştirildiğinden hiçbir veri kaybolmaz. Bir daha İngilizce bölümüne göz atan biri, 8/8/2013 başlangıç tarihi ve Sıfır dolar bütçesi gibi Hem John'un hem de Jane'in değişikliklerini görür.

    Bu güncelleştirme yöntemi, veri kaybına neden olabilecek çakışma sayısını azaltabilir, ancak bir varlığın aynı özelliğinde rakip değişiklikler yapıldığında veri kaybını önleyemez. Entity Framework'ün bu şekilde çalışıp çalışmadığı, güncelleştirme kodunuzu nasıl uyguladığınıza bağlıdır. Bir varlığın tüm özgün özellik değerlerini ve yeni değerleri izlemek için büyük miktarlarda durum korumanızı gerektirebileceğinden, web uygulamasında genellikle pratik değildir. Sunucu kaynakları gerektirdiğinden veya web sayfasının kendisine (örneğin, gizli alanlarda) dahil edilmesi gerektiğinden, büyük miktarlarda durumun korunması uygulama performansını etkileyebilir.

  • Jane'in değişikliğinin John'un değişikliğinin üzerine yazmasına izin vekleyebilirsiniz. Bir daha İngilizce bölümüne göz atılan kişiler 8/8/2013 ve geri yüklenen 350.000,00 ABD doları değerini görür. Buna İstemci Kazanır veya Wins senaryosunda Son denir. (İstemcinin değerleri veri deposundakilerden önceliklidir.) Bu bölüme giriş bölümünde belirtildiği gibi, eşzamanlılık işleme için herhangi bir kodlama yapmazsanız, bu otomatik olarak gerçekleşir.

  • 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 uygulamasına izin verirsiniz. Buna Store Wins senaryosu adı verilir. (Veri deposu değerleri, istemci tarafından gönderilen değerlerden önceliklidir.) Bu öğreticide Store Wins senaryosunu uygulayacaksınız. Bu yöntem, bir kullanıcı olup bitenler konusunda uyarılmadan hiçbir değişikliğin üzerine yazılmamasını sağlar.

Eşzamanlılık Çakışmalarını Algılama

Entity Framework'ün oluşturduğu OptimisticConcurrencyException özel durumlarını işleyerek ç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ı tablosunda, bir satırın ne zaman değiştirildiğini belirlemek için kullanılabilecek bir izleme sütunu ekleyin. Daha sonra Entity Framework'i bu sütunu SQL Update veya Delete komutların Where yan tümcesine dahil etmek üzere yapılandırabilirsiniz.

    İzleme sütununun veri türü genellikle rowversion'dır. Rowversion değeri, satır her güncelleştirildiğinde artırılan sıralı bir sayıdır. veya Update Delete komutunda Where yan tümcesi, izleme sütununun özgün değerini (özgün satır sürümü) içerir. Güncelleştirilmekte olan satır başka bir kullanıcı tarafından değiştirildiyse, sütundaki rowversion değer özgün değerden farklıdır, bu nedenle Update veya Delete deyimi yan tümcesi Where nedeniyle güncelleştirilecek satırı bulamaz. Entity Framework, veya Delete komutu (etkilenen satır sayısı sıfır olduğunda) tarafından Update hiçbir satırın güncelleştirildiğini bulduğunda, bunu eşzamanlılık çakışması olarak yorumlar.

  • Entity Framework'i tablodaki Where her sütunun özgün değerlerini ve Delete komutlarının yan tümcesine Update 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 eşzamanlılık çakışması olarak yorumlar. Çok sayıda sütunu olan veritabanı tablolarında bu yaklaşım çok büyük Where yan tümcelere neden olabilir ve büyük miktarlarda durum korumanızı gerektirebilir. Daha önce belirtildiği gibi, sunucu kaynakları gerektirdiğinden veya web sayfasının kendisine dahil edilmesi gerektiğinden, büyük miktarda durumun korunması uygulama performansını etkileyebilir. Bu nedenle bu yaklaşım genellikle önerilmez ve bu öğreticide kullanılan yöntem değildir.

    Eşzamanlılık için bu yaklaşımı uygulamak istiyorsanız, concurrencyCheck özniteliğini ekleyerek eşzamanlılığı izlemek istediğiniz varlıktaki birincil anahtar olmayan tüm özellikleri işaretlemeniz gerekir. Bu değişiklik Entity Framework'ün deyimlerin SQL WHERE yan tümcesine tüm sütunları eklemesini UPDATE sağlar.

Bu öğreticinin geri kalanında varlığa bir rowversion izleme özelliği Department ekleyecek, bir denetleyici ve görünüm oluşturacak ve her şeyin düzgün çalıştığını doğrulamak için test yapacaksınız.

Departman Varlığına İyimser Eşzamanlılık Özelliği Ekleme

Models\Department.cs içinde adlı RowVersionbir izleme özelliği ekleyin:

public class Department
{
    public int DepartmentID { get; set; }

    [StringLength(50, MinimumLength = 3)]
    public string Name { get; set; }

    [DataType(DataType.Currency)]
    [Column(TypeName = "money")]
    public decimal Budget { get; set; }

    [DataType(DataType.Date)]
    public DateTime StartDate { get; set; }

    [Display(Name = "Administrator")]
    public int? InstructorID { get; set; }

    [Timestamp]
    public byte[] RowVersion { get; set; }

    public virtual Instructor Administrator { get; set; }
    public virtual ICollection<Course> Courses { get; set; }
}

Timestamp özniteliği, bu sütunun veritabanına gönderilen ve Delete komutlarının Update yan tümcesine dahil Where olacağını belirtir. SQL Server'ın önceki sürümleri, SQL rowversion yerine bir SQL zaman damgası veri türü kullandığından, özniteliği zaman damgası olarak adlandırılır. için rowversion .Net türü bir bayt dizisidir. Akıcı API'yi kullanmayı tercih ediyorsanız, aşağıdaki örnekte gösterildiği gibi izleme özelliğini belirtmek için IsConcurrencyToken yöntemini kullanabilirsiniz:

modelBuilder.Entity<Department>()
    .Property(p => p.RowVersion).IsConcurrencyToken();

IsConcurrencyToken by IsRowVersion ile Değiştirme GitHub sorununa bakın.

Bir özellik ekleyerek veritabanı modelini değiştirdiğinizden başka bir geçiş yapmanız gerekir. Paket Yöneticisi Konsolu'na (PMC) aşağıdaki komutları girin:

Add-Migration RowVersion
Update-Database

Bölüm Denetleyicisi Oluşturma

Aşağıdaki ayarları kullanarak bir Department denetleyici oluşturun ve diğer denetleyicilerle aynı şekilde görüntüler:

Add_Controller_dialog_box_for_Department_controller

Controllers\DepartmentController.cs içinde bir using deyim ekleyin:

using System.Data.Entity.Infrastructure;

Bölüm yöneticisi açılan listelerinin yalnızca soyadı yerine eğitmenin tam adını içermesi için bu dosyanın her yerinde "Soyadı" değerini "FullName" olarak değiştirin (dört oluşum).

ViewBag.InstructorID = new SelectList(db.Instructors, "InstructorID", "FullName");

yöntemi için HttpPost Edit mevcut kodu aşağıdaki kodla değiştirin:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
   [Bind(Include = "DepartmentID, Name, Budget, StartDate, RowVersion, InstructorID")]
    Department department)
{
   try
   {
      if (ModelState.IsValid)
      {
         db.Entry(department).State = EntityState.Modified;
         db.SaveChanges();
         return RedirectToAction("Index");
      }
   }
   catch (DbUpdateConcurrencyException ex)
   {
      var entry = ex.Entries.Single();
      var clientValues = (Department)entry.Entity;
      var databaseValues = (Department)entry.GetDatabaseValues().ToObject();

      if (databaseValues.Name != clientValues.Name)
         ModelState.AddModelError("Name", "Current value: "
             + databaseValues.Name);
      if (databaseValues.Budget != clientValues.Budget)
         ModelState.AddModelError("Budget", "Current value: "
             + String.Format("{0:c}", databaseValues.Budget));
      if (databaseValues.StartDate != clientValues.StartDate)
         ModelState.AddModelError("StartDate", "Current value: "
             + String.Format("{0:d}", databaseValues.StartDate));
      if (databaseValues.InstructorID != clientValues.InstructorID)
         ModelState.AddModelError("InstructorID", "Current value: "
             + db.Instructors.Find(databaseValues.InstructorID).FullName);
      ModelState.AddModelError(string.Empty, "The record you attempted to edit "
          + "was modified by another user after you got the original value. The "
          + "edit operation was canceled and the current values in the database "
          + "have been displayed. If you still want to edit this record, click "
          + "the Save button again. Otherwise click the Back to List hyperlink.");
      department.RowVersion = databaseValues.RowVersion;
   }
   catch (DataException /* dex */)
   {
      //Log the error (uncomment dex variable name after DataException and add a line here to write a log.
      ModelState.AddModelError(string.Empty, "Unable to save changes. Try again, and if the problem persists contact your system administrator.");
   }

   ViewBag.InstructorID = new SelectList(db.Instructors, "InstructorID", "FullName", department.InstructorID);
   return View(department);
}

Görünüm, özgün RowVersion değeri gizli bir alanda depolar. Model bağlayıcısı örneği oluşturduğunda department , bu nesne kullanıcının Düzenle sayfasına girdiği gibi özgün RowVersion özellik değerine ve diğer özellikler için yeni değerlere sahip olur. Ardından Entity Framework bir SQL UPDATE komutu oluşturduğunda, bu komut özgün RowVersion değere sahip bir WHERE satırın arandığı bir yan tümcesi içerir.

Komutundan UPDATE hiçbir satır etkilenmezse (özgün RowVersion değere sahip satır yoksa), Entity Framework bir DbUpdateConcurrencyException özel durum oluşturur ve bloktaki catch kod etkilenen varlığı özel durum nesnesinden alır Department . Bu varlık hem veritabanından okunan değerlere hem de kullanıcı tarafından girilen yeni değerlere sahiptir:

var entry = ex.Entries.Single();
var clientValues = (Department)entry.Entity;
var databaseValues = (Department)entry.GetDatabaseValues().ToObject();

Ardından kod, kullanıcının Düzenle sayfasına girdiği değerlerden farklı veritabanı değerlerine sahip her sütun için özel bir hata iletisi ekler:

if (databaseValues.Name != currentValues.Name)
    ModelState.AddModelError("Name", "Current value: " + databaseValues.Name);
    // ...

Daha uzun bir hata iletisinde neler olduğu ve bu konuda yapılması gerekenler açıklanmaktadır:

ModelState.AddModelError(string.Empty, "The record you attempted to edit "
    + "was modified by another user after you got the original value. The"
    + "edit operation was canceled and the current values in the database "
    + "have been displayed. If you still want to edit this record, click "
    + "the Save button again. Otherwise click the Back to List hyperlink.");

Son olarak, kod nesnenin Department değerini veritabanından alınan yeni değere ayarlarRowVersion. Bu yeni RowVersion değer, Düzenle sayfası yeniden görüntülendiğinde ve kullanıcı Kaydet'e bir sonraki tıkladığında, yalnızca Düzenle sayfasının yeniden dağıtılmasından bu yana oluşan eşzamanlılık hataları yakalandığında gizli alanda depolanır.

Views\Department\Edit.cshtml içinde, özelliğin RowVersion gizli alanını hemen izleyerek özellik değerini kaydetmek için DepartmentID gizli bir alan ekleyin:

@model ContosoUniversity.Models.Department

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Department</legend>

        @Html.HiddenFor(model => model.DepartmentID)
        @Html.HiddenFor(model => model.RowVersion)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>

Views\Department\Index.cshtml içinde, satır bağlantılarını sola taşımak için var olan kodu aşağıdaki kodla değiştirin ve Yönetici sütunu yerine LastName görüntülenecek FullName sayfa başlığı ve sütun başlıklarını değiştirin:

@model IEnumerable<ContosoUniversity.Models.Department>

@{
    ViewBag.Title = "Departments";
}

<h2>Departments</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th></th>
        <th>Name</th>
        <th>Budget</th>
        <th>Start Date</th>
        <th>Administrator</th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |
            @Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Budget)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.StartDate)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Administrator.FullName)
        </td>
    </tr>
}

</table>

İyimser Eşzamanlılık İşlemeyi Test Etme

Siteyi çalıştırın ve Departmanlar'a tıklayın:

Contoso Üniversite Bölümleri sayfasını gösteren ekran görüntüsü.

Kim Abercrombie için Düzenle köprüsüne sağ tıklayın ve Yeni sekmede aç'ı seçin, ardından Kim Abercrombie için köprüyü düzenle'ye tıklayın. İki pencere aynı bilgileri görüntüler.

Department_Edit_page_before_changes

İlk tarayıcı penceresinde bir alanı değiştirin ve Kaydet'e tıklayın.

Department_Edit_page_1_after_change

Tarayıcı, değiştirilen değere sahip Dizin sayfasını gösterir.

Departments_Index_page_after_first_budget_edit

İkinci tarayıcı penceresindeki herhangi bir alanı değiştirin ve Kaydet'e tıklayın.

Department_Edit_page_2_after_change

İkinci tarayıcı penceresinde Kaydet'e tıklayın. Bir hata iletisi görürsünüz:

Kullanıcının yeniden Kaydet'i seçmesine hazır bir hata iletisi içeren Üniversite sayfasını gösteren ekran görüntüsü.

Yeniden Kaydet'e tıklayın. İkinci tarayıcıya girdiğiniz değer, ilk tarayıcıda değiştirdiğiniz verilerin özgün değeriyle birlikte kaydedilir. Dizin sayfası görüntülendiğinde kaydedilen değerleri görürsünüz.

Department_Index_page_with_change_from_second_browser

Silme Sayfasını Güncelleştirme

Sil sayfasında Entity Framework, departmanı benzer şekilde düzenleyen başka birinin neden olduğu eşzamanlılık çakışmalarını algılar. HttpGet Delete Yöntem onay görünümünü görüntülediğinde, görünüm gizli bir alandaki özgün RowVersion değeri içerir. Bu değer daha sonra kullanıcı silme işlemini HttpPost Delete onayladığında çağrılan yöntem tarafından kullanılabilir. Entity Framework SQL DELETE komutunu oluşturduğunda özgün RowVersion değere sahip bir WHERE yan tümcesi içerir. Komut etkilenen sıfır satırla sonuçlanırsa (silme onay sayfası görüntülendikten sonra satır değiştirildi anlamına gelir), eşzamanlılık özel durumu oluşturulur ve HttpGet Delete yöntem, onay sayfasını bir hata iletisiyle yeniden görüntülemek için olarak ayarlanmış true bir hata bayrağıyla çağrılır. Satır başka bir kullanıcı tarafından silindiğinden sıfır satır da etkilenmiş olabilir, bu durumda farklı bir hata iletisi görüntülenir.

DepartmentController.cs'da yöntemini aşağıdaki kodla değiştirin HttpGet Delete:

public ActionResult Delete(int id, bool? concurrencyError)
{
    Department department = db.Departments.Find(id);

    if (concurrencyError.GetValueOrDefault())
    {
        if (department == null)
        {
            ViewBag.ConcurrencyErrorMessage = "The record you attempted to delete "
                + "was deleted by another user after you got the original values. "
                + "Click the Back to List hyperlink.";
        }
        else
        {
            ViewBag.ConcurrencyErrorMessage = "The record you attempted to delete "
                + "was modified by another user after you got the original values. "
                + "The delete operation was canceled and the current values in the "
                + "database have been displayed. If you still want to delete this "
                + "record, click the Delete button again. Otherwise "
                + "click the Back to List hyperlink.";
        }
    }

    return View(department);
}

yöntemi, bir eşzamanlılık hatasından sonra sayfanın yeniden dağıtılıp dağıtılmadığını gösteren isteğe bağlı bir parametre kabul eder. Bu bayrak ise true, bir özellik kullanılarak görünüme bir ViewBag hata iletisi gönderilir.

yöntemindeki HttpPost Delete (adlandırılmış DeleteConfirmed) kodu aşağıdaki kodla değiştirin:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(Department department)
{
    try
    {
        db.Entry(department).State = EntityState.Deleted;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    catch (DbUpdateConcurrencyException)
    {
        return RedirectToAction("Delete", new { concurrencyError=true } );
    }
    catch (DataException /* dex */)
    {
        //Log the error (uncomment dex variable name after DataException and add a line here to write a log.
        ModelState.AddModelError(string.Empty, "Unable to delete. Try again, and if the problem persists contact your system administrator.");
        return View(department);
    }
}

Yeni değiştirdiğiniz yapı iskelesi oluşturulmuş kodda, bu yöntem yalnızca bir kayıt kimliğini kabul etti:

public ActionResult DeleteConfirmed(int id)

Bu parametreyi model bağlayıcısı tarafından oluşturulan bir Department varlık örneğiyle değiştirdiniz. Bu, kayıt anahtarına RowVersion ek olarak özellik değerine erişmenizi sağlar.

public ActionResult Delete(Department department)

Eylem yöntemi adını DeleteConfirmed olarak da değiştirdiniz Delete. yöntemine benzersiz bir imza vermek için yöntemi DeleteConfirmed adlı HttpPost Delete yapı iskelesi HttpPost oluşturulmuş kod. (CLR, farklı yöntem parametrelerine sahip olmak için aşırı yüklenmiş yöntemler gerektirir.) artık imzalar benzersiz olduğuna göre, MVC kuralına bağlı kalıp ve HttpGet silme yöntemleri için HttpPost aynı adı kullanabilirsiniz.

Eşzamanlılık hatası yakalanırsa, kod Silme onay sayfasını yeniden görüntüler ve eşzamanlılık hata iletisi görüntülemesi gerektiğini belirten bir bayrak sağlar.

Views\Department\Delete.cshtml içinde, yapı iskelesi oluşturulmuş kodu bazı biçimlendirme değişiklikleri yapan ve hata iletisi alanı ekleyen aşağıdaki kodla değiştirin. Değişiklikler vurgulanır.

@model ContosoUniversity.Models.Department

@{
    ViewBag.Title = "Delete";
}

<h2>Delete</h2>

<p class="error">@ViewBag.ConcurrencyErrorMessage</p>

<h3>Are you sure you want to delete this?</h3>
<fieldset>
    <legend>Department</legend>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.Name)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Name)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.Budget)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Budget)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.StartDate)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.StartDate)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.Administrator.FullName)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Administrator.FullName)
    </div>
</fieldset>
@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
   @Html.HiddenFor(model => model.DepartmentID)
    @Html.HiddenFor(model => model.RowVersion)
    <p>
        <input type="submit" value="Delete" /> |
        @Html.ActionLink("Back to List", "Index")
    </p>
}

Bu kod ve h3 başlıkları arasına h2 bir hata iletisi ekler:

<p class="error">@ViewBag.ConcurrencyErrorMessage</p>

şunun yerine LastName FullName alanında değerini alır Administrator :

<div class="display-label">
    @Html.LabelFor(model => model.InstructorID)
</div>
<div class="display-field">
    @Html.DisplayFor(model => model.Administrator.FullName)
</div>

Son olarak, deyiminden DepartmentID sonra Html.BeginForm ve RowVersion özellikleri için gizli alanlar ekler:

@Html.HiddenFor(model => model.DepartmentID)
@Html.HiddenFor(model => model.RowVersion)

Departmanlar Dizini sayfasını çalıştırın. İngilizce bölümü için Sil köprüsüne sağ tıklayın ve Yeni pencerede aç'ı seçin, sonra ilk pencerede İngilizce bölümü için Düzenle köprüsüne tıklayın.

İlk pencerede değerlerden birini değiştirin ve Kaydet'e tıklayın:

Department_Edit_page_after_change_before_delete

Dizin sayfası değişikliği onaylar.

Departments_Index_page_after_budget_edit_before_delete

İkinci pencerede Sil'e tıklayın.

Department_Delete_confirmation_page_before_concurrency_error

Eşzamanlılık hata iletisini görürsünüz ve Departman değerleri şu anda veritabanındaki değerlerle yenilenir.

Department_Delete_confirmation_page_with_concurrency_error

Sil'e yeniden tıklarsanız, bölümün silindiğini gösteren Dizin sayfasına yönlendirilirsiniz.

Özet

Bu, eşzamanlılık çakışmalarını işlemeye giriş işlemini tamamlar. Çeşitli eşzamanlılık senaryolarını işlemenin diğer yolları hakkında bilgi için Entity Framework ekip blogundaki İyimser Eşzamanlılık Desenleri ve Özellik Değerleriyle Çalışma konularına bakın. Sonraki öğreticide ve Student varlıkları için Instructor hiyerarşi başına tablo devralmayı uygulama gösterilmektedir.

Diğer Entity Framework kaynaklarına bağlantılar ASP.NET Veri Erişimi İçerik Eşlemesi'nde bulunabilir.