Öğretici: ASP.NET MVC 5 uygulamasında EF ile Eşzamanlılığı İşleme

Önceki öğreticilerde verileri güncelleştirme hakkında bilgi edindiyseniz. Bu öğreticide, birden çok kullanıcı aynı varlığı aynı anda güncelleştirdiğinde çakışmaları işlemek için iyimser eşzamanlılığın nasıl kullanılacağı gösterilmektedir. Varlıkla Department çalışan web sayfalarını eşzamanlılık hatalarını işleyecek şekilde değiştirirsiniz. Aşağıdaki çizimlerde, eşzamanlılık çakışması oluştuğunda görüntülenen bazı iletiler de dahil olmak üzere Düzenle ve Sil sayfaları gösterilmektedir.

Bölüm Adı, Bütçe, Başlangıç Tarihi ve Yönetici değerlerinin vurgulandığı Düzenle sayfasını gösteren ekran görüntüsü.

Silme işlemi ve Sil düğmesi hakkında bir ileti içeren kaydın Sil sayfasını gösteren ekran görüntüsü.

Bu öğreticide şunları yaptınız:

  • Eşzamanlılık çakışmaları hakkında bilgi edinin
  • İyimser eşzamanlılık ekleme
  • Bölüm denetleyicisini değiştirme
  • Eşzamanlılık işlemeyi test etme
  • Sil sayfasını güncelleştirme

Önkoşullar

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

Bir kullanıcı bir varlığın verilerini düzenlemek üzere görüntülediğinde ve ardından ilk kullanıcının değişikliği veritabanına yazılmadan önce başka bir kullanıcı aynı varlığın verilerini güncelleştirdiğinde eşzamanlılık çakışması oluşur. Bu tür çakışmaların algılanması etkinleştirilmezse, 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: az sayıda 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. 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, başka hiçbir kullanıcının salt okunur erişim veya güncelleştirme erişimi için satırı kilitlemesine izin verilmez çünkü değiştirilme sürecinde olan verilerin bir kopyasını alabilirler. Bir satırı salt okunur erişim için kilitlerseniz, başkaları da 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. 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 ve İngilizce departmanının Bütçe tutarını 350.000,00 TL'den 0,00 TL'ye değiştirir.

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.

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, hem John'un hem de Jane'in değişikliklerini görür. Başlangıç tarihi 8/8/2013 ve sıfır dolar bütçesi.

    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 tutmanızı gerektirebileceğinden, web uygulamasında genellikle pratik değildir. Sunucu kaynakları gerektirdiğinden veya web sayfasının kendisine (örneğin, gizli alanlara) veya tanımlama bilgisine 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. İngilizce bölümüne bir sonraki göz atışında 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 adı verilir. (İstemcideki tüm değerler veri deposundakilerden önceliklidir.) Bu bölüme girişte 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şiklikleri 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. bir Update veya 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 nedeniyle Where güncelleştirilecek satırı bulamaz. Entity Framework, veya Delete komutu tarafından hiçbir satırın Update güncelleştirildiğini bulduğunda (etkilenen satır sayısı sıfır olduğ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 içerecek şekilde 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. Çok sayıda sütunu olan veritabanı tablolarında bu yaklaşım çok büyük Where yan tümcelerle sonuçlanabilir ve büyük miktarlarda durum tutmanızı gerektirebilir. Daha önce belirtildiği gibi, büyük miktarlarda 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ığa yönelik bu yaklaşımı uygulamak istiyorsanız, eşzamanlılığı izlemek istediğiniz varlıktaki tüm birincil anahtar olmayan özellikleri bunlara ConcurrencyCheck özniteliğini ekleyerek işaretlemeniz gerekir. Bu değişiklik Entity Framework'ün deyimlerin SQL WHERE yan tümcesindeki tüm sütunları içermesini 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.

İyimser eşzamanlılık 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)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    [Display(Name = "Start 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 eklendiğini Where belirtir. SQL Server'nin önceki sürümleri, SQL rowversion tarafından değiştirilmeden önce bir SQL zaman damgası veri türü kullandığından, özniteliği Zaman Damgası olarak adlandırılır. Rowversion için .Net türü bir bayt dizisidir.

Fluent API 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();

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

Add-Migration RowVersion
Update-Database

Bölüm denetleyicisini değiştirme

Controllers\DepartmentController.cs dosyasına bir using deyim ekleyin:

using System.Data.Entity.Infrastructure;

DepartmentController.cs dosyasında, bölüm yöneticisi açılan listelerinin yalnızca soyadı yerine eğitmenin tam adını içermesi için dört "Soyadı" örneğini de "FullName" olarak değiştirin.

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

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

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(int? id, byte[] rowVersion)
{
    string[] fieldsToBind = new string[] { "Name", "Budget", "StartDate", "InstructorID", "RowVersion" };

    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    var departmentToUpdate = await db.Departments.FindAsync(id);
    if (departmentToUpdate == null)
    {
        Department deletedDepartment = new Department();
        TryUpdateModel(deletedDepartment, fieldsToBind);
        ModelState.AddModelError(string.Empty,
            "Unable to save changes. The department was deleted by another user.");
        ViewBag.InstructorID = new SelectList(db.Instructors, "ID", "FullName", deletedDepartment.InstructorID);
        return View(deletedDepartment);
    }

    if (TryUpdateModel(departmentToUpdate, fieldsToBind))
    {
        try
        {
            db.Entry(departmentToUpdate).OriginalValues["RowVersion"] = rowVersion;
            await db.SaveChangesAsync();

            return RedirectToAction("Index");
        }
        catch (DbUpdateConcurrencyException ex)
        {
            var entry = ex.Entries.Single();
            var clientValues = (Department)entry.Entity;
            var databaseEntry = entry.GetDatabaseValues();
            if (databaseEntry == null)
            {
                ModelState.AddModelError(string.Empty,
                    "Unable to save changes. The department was deleted by another user.");
            }
            else
            {
                var databaseValues = (Department)databaseEntry.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.");
                departmentToUpdate.RowVersion = databaseValues.RowVersion;
            }
        }
        catch (RetryLimitExceededException /* dex */)
        {
            //Log the error (uncomment dex variable name and add a line here to write a log.)
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
        }
    }
    ViewBag.InstructorID = new SelectList(db.Instructors, "ID", "FullName", departmentToUpdate.InstructorID);
    return View(departmentToUpdate);
}

FindAsync Yöntem null döndürürse, bölüm başka bir kullanıcı tarafından silindi. Gösterilen kod, düzenle sayfasının bir hata iletisiyle yeniden görüntülenebilmesi için bir departman varlığı oluşturmak için deftere nakledilen form değerlerini kullanır. Alternatif olarak, departman alanlarını yeniden görüntülemeden yalnızca bir hata iletisi görüntülüyorsanız departman varlığını yeniden oluşturmanız gerekmez.

Görünüm, özgün RowVersion değeri gizli bir alanda depolar ve yöntemi bunu parametresinde rowVersion alır. çağrısı SaveChangesyapmadan önce, varlığın koleksiyonuna OriginalValues bu özgün RowVersion özellik değerini koymanız gerekir. Ardından Entity Framework bir SQL UPDATE komutu oluşturduğunda, bu komut özgün RowVersion değere sahip bir satırın arandığı bir yan tümcesi içerirWHERE.

Komuttan 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 .

var entry = ex.Entries.Single();

Bu nesnenin özelliğinde Entity kullanıcı tarafından girilen yeni değerler var ve yöntemini çağırarak GetDatabaseValues değerleri veritabanından okuyabilirsiniz.

var clientValues = (Department)entry.Entity;
var databaseEntry = entry.GetDatabaseValues();

Biri GetDatabaseValues veritabanından satırı silmişse yöntemi null döndürür; aksi takdirde, özelliklere erişmek Department için Department döndürülen nesneyi sınıfına atamanız gerekir. (Silmeyi zaten denetlediğiniz için, databaseEntry yalnızca departman yürütüldükten sonra FindAsync ve yürütülmeden önce SaveChanges silindiyse null olur.)

if (databaseEntry == null)
{
    ModelState.AddModelError(string.Empty,
        "Unable to save changes. The department was deleted by another user.");
}
else
{
    var databaseValues = (Department)databaseEntry.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 ne olduğu ve bu konuda yapılması gerekenler açıklanı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, nesnesinin RowVersionDepartment değerini veritabanından alınan yeni değere ayarlar. Bu yeni RowVersion değer, Düzenle sayfası yeniden görüntülendiğinde gizli alanda depolanır ve kullanıcı Kaydet'e bir sonraki tıkladığında, yalnızca Düzenle sayfasının yeniden dağıtılmasından sonra oluşan eşzamanlılık hataları yakalanacaktır.

Views\Department\Edit.cshtml içinde, özelliğin RowVersion gizli alanının hemen ardından ö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()
    
    <div class="form-horizontal">
        <h4>Department</h4>
        <hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.DepartmentID)
        @Html.HiddenFor(model => model.RowVersion)

Eşzamanlılık işlemeyi test etme

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

İngilizce bölümü için Düzenle köprüsüne sağ tıklayın ve Yeni sekmede aç'ı seçin, ardından İngilizce bölümü için Düzenle köprüsüne tıklayın. İki sekme aynı bilgileri görüntüler.

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

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

İkinci tarayıcı sekmesindeki bir alanı değiştirin ve Kaydet'e tıklayın. Bir hata iletisi görürsünüz:

Ekran görüntüsü, değerin başka bir kullanıcı tarafından değiştirildiği için işlemin iptal edildiğini açıklayan bir iletinin bulunduğu Düzenle sayfasını gösterir.

Yeniden Kaydet'e tıklayın. İkinci tarayıcı sekmesine 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.

Sil sayfasını güncelleştirme

Silme sayfasında Entity Framework, departmanı benzer şekilde düzenleyen başka birinin neden olduğu eşzamanlılık çakışmalarını algılar. HttpGetDelete Yöntem onay görünümünü görüntülediğinde, görünüm gizli bir alanda özgün RowVersion değeri içerir. Bu değer daha sonra kullanıcı silme işlemini HttpPostDelete onayladığında çağrılan yöntemi 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ın değiştirildiği anlamına gelir), bir eşzamanlılık özel durumu oluşturulur ve HttpGet Delete onay sayfasını bir hata iletisiyle yeniden görüntülemek için hata bayrağı ayarlanmış true yöntem ç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 dosyasında yöntemini aşağıdaki kodla değiştirinHttpGetDelete:

public async Task<ActionResult> Delete(int? id, bool? concurrencyError)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Department department = await db.Departments.FindAsync(id);
    if (department == null)
    {
        if (concurrencyError.GetValueOrDefault())
        {
            return RedirectToAction("Index");
        }
        return HttpNotFound();
    }

    if (concurrencyError.GetValueOrDefault())
    {
        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 görüntülenip görüntülenmediğini 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 HttpPostDelete (adlandırılmış DeleteConfirmed) kodu aşağıdaki kodla değiştirin:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Delete(Department department)
{
    try
    {
        db.Entry(department).State = EntityState.Deleted;
        await db.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    catch (DbUpdateConcurrencyException)
    {
        return RedirectToAction("Delete", new { concurrencyError = true, id=department.DepartmentID });
    }
    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 async Task<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 async Task<ActionResult> Delete(Department department)

Eylem yöntemi adını DeleteConfirmedDeleteolarak da değiştirdiniz. yöntemine benzersiz bir imza vermek için yöntemi DeleteConfirmed adlı HttpPostDelete yapı iskelesi oluşturulmuş HttpPost 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 bir eşzamanlılık hata iletisi görüntülemesi gerektiğini belirten bir bayrak sağlar.

Views\Department\Delete.cshtml içinde, iskelesi oluşturulmuş kodu, DepartmentID ve RowVersion özellikleri için bir hata iletisi alanı ve gizli alanlar 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>
<div>
    <h4>Department</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            Administrator
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Administrator.FullName)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Name)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Name)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.Budget)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Budget)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.StartDate)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.StartDate)
        </dd>

    </dl>

    @using (Html.BeginForm()) {
        @Html.AntiForgeryToken()
        @Html.HiddenFor(model => model.DepartmentID)
        @Html.HiddenFor(model => model.RowVersion)

        <div class="form-actions no-color">
            <input type="submit" value="Delete" class="btn btn-default" /> |
            @Html.ActionLink("Back to List", "Index")
        </div>
    }
</div>

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

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

alanındaki ile FullNameAdministrator değiştirilirLastName:

<dt>
  Administrator
</dt>
<dd>
  @Html.DisplayFor(model => model.Administrator.FullName)
</dd>

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 sekmede aç'ı seçin, ardından ilk sekmede İ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.

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

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

Eşzamanlılık hata iletisini görürsünüz ve Departman değerleri veritabanındakilerle 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.

Kodu alma

Tamamlanan Projeyi İndir

Ek kaynaklar

Diğer Entity Framework kaynaklarına bağlantılar ASP.NET Veri Erişimi - Önerilen Kaynaklar bölümünde bulunabilir.

Çeşitli eşzamanlılık senaryolarını işlemenin diğer yolları hakkında bilgi için bkz. İyimser Eşzamanlılık Desenleri ve MSDN'de Özellik Değerleriyle Çalışma . Sonraki öğreticide ve Student varlıkları için Instructor hiyerarşi başına tablo devralmayı uygulama gösterilmektedir.

Sonraki adımlar

Bu öğreticide şunları yaptınız:

  • Eşzamanlılık çakışmaları hakkında bilgi edinildi
  • İyimser eşzamanlılık eklendi
  • Değiştirilen Departman denetleyicisi
  • Test edilen eşzamanlılık işleme
  • Sil sayfası güncelleştirildi

Veri modelinde devralmayı uygulamayı öğrenmek için sonraki makaleye ilerleyin.