Öğretici: bir ASP.NET MVC 5 uygulamasında EF ile eşzamanlılık Işleme

Önceki öğreticilerde, verileri güncelleştirme hakkında daha fazla öğrenirsiniz. Bu öğreticide, birden fazla kullanıcı aynı anda aynı varlığı güncelleştirilişinde, çakışmaları işlemek için iyimser eşzamanlılık kullanımı gösterilmektedir. Department varlıkla birlikte çalışan Web sayfalarını, eşzamanlılık hatalarını işleyecek şekilde değiştirirsiniz. Aşağıdaki çizimler, bir eşzamanlılık çakışması oluşursa görüntülenen bazı iletiler dahil olmak üzere, düzenleme ve silme sayfalarını gösterir.

Department_Edit_page_2_after_clicking_Save

Department_Edit_page_2_after_clicking_Save

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

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

Önkoşullar

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

Bir Kullanıcı bir varlığın verilerini düzenlemek için bir varlık verileri görüntülediğinde bir eşzamanlılık çakışması oluşur ve sonra, ilk kullanıcının değişikliği veritabanına yazılmadan önce diğer Kullanıcı aynı varlığın verilerini günceller. Bu tür çakışmaların algılanmasını etkinleştirmezseniz, veritabanını güncelleştirme son olarak diğer kullanıcının değişikliklerinin üzerine yazar. Birçok uygulamada, bu risk kabul edilebilir: birkaç Kullanıcı veya birkaç güncelleştirme varsa veya bazı değişikliklerin üzerine yazılırsa gerçekten önemli değilse, eşzamanlılık için programlama maliyeti avantajdan yararlanabilir. Bu durumda, uygulamayı eşzamanlılık çakışmalarını işleyecek şekilde 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 yapmanın bir yolu veritabanı kilitlerini kullanmaktır. Bu, Kötümser eşzamanlılıkolarak adlandırılır. Örneğin, bir veritabanından bir satırı okuyabilmeniz için, salt okunurdur veya güncelleştirme erişimi için bir kilit isteyin. Bir satırı güncelleştirme erişimi için kilitlerseniz, başka hiçbir kullanıcının satırı değiştirme sürecinde olan verilerin bir kopyasını alması için salt okunurdur veya güncelleştirme erişimi için bu satırı kilitlemesine izin verilmez. Bir satırı salt okuma erişimi için kilitlerseniz, diğerleri dosyayı salt okuma erişimi için de kilitleyip güncelleştirme için de kilitleyebilirler.

Kilitleri yönetmek dezavantajlara sahiptir. Program, 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ık 'yi desteklemez. Entity Framework, BT için yerleşik destek sağlamaz ve bu öğretici bunu nasıl uygulayacağınızı göstermez.

İyimser Eşzamanlılık

Kötümser eşzamanlılık yerine iyimsereşzamanlılık yapılır. İyimser eşzamanlılık, eşzamanlılık çakışmalarının gerçekleşmesine ve sonra uygun şekilde yeniden davranmasını sağlar. Örneğin John, departmanlar düzenleme sayfasını çalıştırıyorsa, Ingilizce departmanı $350.000,00 olan Bütçe tutarını $0,00 olarak değiştirir.

John, Kaydet' i tıklamadan önce, kemal aynı sayfayı çalıştırır ve başlangıç tarihi alanını 9/1/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ği görür, sonra gamze Kaydet' i tıklatır. Sonraki işlemin ne eşzamanlılık çakışmalarını nasıl ele tarafından belirlenir. Bazı seçenekler şunlardır:

  • Bir kullanıcının hangi özelliği değiştirdiği ve yalnızca ilgili sütunları veritabanında güncelleştirdiğinden haberdar olabilirsiniz. Örnek senaryoda, iki kullanıcı tarafından farklı özellikler güncelleştirildiğinden hiçbir veri kaybolmaz. Ingilizce bölüme bir dahaki sefer ilk kez gözattığında, 8/8/2013 başlangıç tarihi ve sıfır dolar bütçesine sahip olan John 'ın ve kemal 'in yaptığı değişiklikleri görürler.

    Bu güncelleştirme yöntemi, veri kaybına neden olabilecek çakışmaların sayısını azaltabilir, ancak bir varlığın aynı özelliğinde rekabet değişiklikleri yapılırsa veri kaybını önleyebilir. Entity Framework bu şekilde çalışıp çalışmadığını, güncelleştirme kodunuzu nasıl uygulayadığınıza bağlıdır. Genellikle bir Web uygulamasında pratik değildir, çünkü bir varlığın tüm özgün özellik değerlerini ve yeni değerleri izlemek için büyük miktarlarda durum tutmanızı gerektirebilir. Büyük miktarlarda durum bulundurma, uygulama performansını etkileyebilir çünkü sunucu kaynakları gerektirir ya da Web sayfasının kendisine (örneğin, gizli alanlarda) veya bir tanımlama bilgisinde yer almalıdır.

  • Gamze 'nin değişikliğini John 'ın değişikliğini geçersiz kılabilirsiniz. Ingilizce bölüme bir dahaki sefer gözattığında, 8/8/2013 ve geri yüklenen $350.000,00 değerini görür. Bu, Istemci WINS veya son WINS senaryosu olarak adlandırılır. (İstemciden gelen tüm değerler veri deposunda yer alacak şekilde önceliklidir.) Bu bölümün 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.

  • Gamze 'nin değişikliğini veritabanında güncelleştirilmesini engelleyebilirsiniz. Genellikle bir hata iletisi görüntüler, verilerin geçerli durumunu gösterir ve yine de yapmak istiyorsa, kendi değişikliklerini yeniden uygular. Buna Mağaza WINS senaryosu denir. (Veri deposu değerleri, istemci tarafından gönderilen değerlere göre önceliklidir.) Bu öğreticide mağaza WINS senaryosunu uygulayacaksınız. Bu yöntem, bir kullanıcının neler olduğunu bildirmeden önce hiçbir değişikliğin üzerine yazılmamasını sağlar.

Eşzamanlılık çakışmalarını algılama

Entity Framework oluşturduğu OptimisticConcurrencyException özel durumlarını işleyerek çakışmaları çözebilirsiniz. Bu özel durumların ne zaman throw hakkında bilgi edinmek için Entity Framework çakışmaları algılayabilmelidir. 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 belirlemede kullanılabilecek bir izleme sütunu ekleyin. Daha sonra Entity Framework SQL Update veya Delete komutlarının Where yan tümcesinde bu sütunu içerecek şekilde yapılandırabilirsiniz.

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

  • Entity Framework, Update ve Delete komutlarının Where yan tümcesindeki tablodaki her sütunun özgün değerlerini içerecek şekilde yapılandırın.

    İlk seçenekte olduğu gibi, satırdaki herhangi bir şey satırın ilk okuduğundan beri değiştiyse, Where yan tümcesi güncelleştirilecek bir satır döndürmez, bu da Entity Framework eşzamanlılık çakışması olarak yorumlar. Birçok sütunu olan veritabanı tablolarında, bu yaklaşım çok büyük Where yan tümceleri oluşmasına neden olabilir ve büyük miktarlarda durum tutmanızı gerektirebilir. Daha önce belirtildiği gibi, büyük miktarlarda durumu korumak uygulama performansını etkileyebilir. Bu nedenle bu yaklaşım genellikle önerilmez ve bu öğreticide kullanılan yöntem değildir.

    Bu yaklaşımı eşzamanlılık 'e uygulamak istiyorsanız, ConcurrencyCheck özniteliğini bunlara ekleyerek eşzamanlılık izlemek istediğiniz varlıktaki tüm birincil anahtar olmayan Özellikleri işaretlemeniz gerekir. Bu değişiklik, Entity Framework UPDATE deyimlerinin SQL WHERE yan tümcesindeki tüm sütunları içermesini sağlar.

Bu öğreticinin geri kalanında Department varlığına bir ROWVERSION izleme özelliği ekleyecek, bir denetleyici ve görünümler oluşturacak ve her şeyin doğru şekilde çalıştığını doğrulamak için test edeceksiniz.

İyimser eşzamanlılık ekleyin

Models\Department.csiçinde RowVersionadlı bir 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 Update ve Delete komutlarının Where yan tümcesine dahil edileceğini belirtir. Önceki SQL Server sürümleri, SQL ROWVERSION tarafından DEĞIŞTIRILMEDEN önce SQL zaman damgası veri türü kullandığından özniteliğe zaman damgası adı verilir. 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ğiniz için başka bir geçiş yapmanız gerekir. Paket Yöneticisi konsolunda (PMC) aşağıdaki komutları girin:

Add-Migration RowVersion
Update-Database

Bölüm denetleyicisini değiştirme

Controllers\DepartmentController.csiçinde using bir ifade ekleyin:

using System.Data.Entity.Infrastructure;

DepartmentController.cs dosyasında, "LastName" sözcüğünün dört yinelemesini "FullName" olarak değiştirin, böylece Departman Yöneticisi açılan listeleri yalnızca soyadı değil, eğitmenin tam adını içerecektir.

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

HttpPost Edit yöntemi için mevcut kodu şu 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öntemi null döndürürse, departman başka bir kullanıcı tarafından silindi. Gösterilen kod, düzenleme sayfasının bir hata iletisiyle yeniden görüntülenebilmesi için bir departman varlığı oluşturmak üzere postalanan form değerlerini kullanır. Alternatif olarak, departman alanlarını yeniden görüntülemeden yalnızca bir hata iletisi görüntülediğinizde, departman varlığını yeniden oluşturmanız gerekmez.

Görünüm özgün RowVersion değerini gizli bir alana depolar ve yöntemi bunu rowVersion parametresinde alır. SaveChangesçağırmadan önce, bu özgün RowVersion özellik değerini varlık için OriginalValues koleksiyonuna koymanız gerekir. Ardından Entity Framework bir SQL UPDATE komutu oluşturduğunda, bu komut orijinal RowVersion değerine sahip bir satırı gösteren bir WHERE yan tümcesi içerecektir.

UPDATE komutundan hiçbir satır etkilenmiyorsa (özgün RowVersion değerine sahip hiçbir satır yoksa), Entity Framework DbUpdateConcurrencyException özel durumu oluşturur ve catch bloğundaki kod, özel durum nesnesinden etkilenen Department varlığını alır.

var entry = ex.Entries.Single();

Bu nesne, Kullanıcı tarafından Entity özelliğinde girilen yeni değerleri içerir ve GetDatabaseValues yöntemini çağırarak veritabanından okunan değerleri alabilirsiniz.

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

GetDatabaseValues yöntemi, bir kullanıcı veritabanından satırı siliyorsa null değerini döndürür; Aksi takdirde, Department özelliklerine erişebilmek için döndürülen nesneyi Department sınıfına atamalısınız. (Zaten silme işlemi yaptığınız için databaseEntry, yalnızca bölüm FindAsync yürütüldükten sonra ve SaveChanges yürütmeden önce silinmişse 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();

Daha sonra, kod, Kullanıcı tarafından düzenleme sayfasına girilen verilerden farklı olan her bir 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 iletisi ne olduğunu ve bunun ne yapılacağını açıklar:

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, Department nesnesinin RowVersion değerini veritabanından alınan yeni değer olarak ayarlar. Bu yeni RowVersion değeri, düzenleme sayfası yeniden görüntülenirken gizli alanda saklanır ve Kullanıcı Kaydet' i tıkladığında, düzenleme sayfasının yeniden görüntülenmesinden bu yana yalnızca gerçekleşen eşzamanlılık hataları yakalanacaktır.

Views\Department\Edit.cshtml' de, DepartmentID özelliğinin Gizli alanını hemen takip eden RowVersion özellik değerini kaydetmek için bir gizli 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.

Ingilizce departman için düzenleme köprüsüne sağ tıklayın ve Yeni sekmesinde aç ' ı seçin ve ardından İngilizce bölümünün düzenleme Köprüsü ' ne tıklayın. İki sekme aynı bilgileri görüntüler.

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

Tarayıcı, değiştirilen değeri olan dizin sayfasını gösterir.

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

Department_Edit_page_2_after_clicking_Save

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ğeri ile birlikte kaydedilir. Dizin sayfası göründüğünde kaydedilen değerleri görürsünüz.

Silme sayfası

Silme sayfası için Entity Framework, başka birinin departmanı benzer bir şekilde düzenlemesinden kaynaklanan eşzamanlılık çakışmalarını algılar. HttpGet Delete yöntemi onay görünümünü görüntülediğinde, görünüm, gizli bir alanda orijinal RowVersion değerini içerir. Bu değer daha sonra Kullanıcı silme işlemini onayladığında çağrılan HttpPost Delete yöntemi için kullanılabilir. Entity Framework, SQL DELETE komutu oluşturduğunda, özgün RowVersion değerine sahip bir WHERE yan tümcesi içerir. Komut, sıfır satır etkilemesiyle sonuçlanırsa (satır silme onayı sayfası görüntülendikten sonra değiştirildiğinde), bir eşzamanlılık özel durumu oluşturulur ve onay sayfasını bir hata iletisiyle yeniden görüntülemek için HttpGet Delete yöntemi bir hata bayrağıyla true olarak çağırılır. Satır başka bir kullanıcı tarafından silindiği için sıfır satır etkilendi ve bu durumda farklı bir hata iletisi görüntülenir.

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

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, sayfanın bir eşzamanlılık hatasından sonra yeniden görüntülenip görüntülenmeyeceğini belirten isteğe bağlı bir parametresini kabul eder. Bu bayrak true, bir ViewBag özelliği kullanılarak görünüme bir hata mesajı gönderilir.

HttpPost Delete yönteminde (DeleteConfirmedadlı) 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);
    }
}

Az önce değiştirdiğiniz scafkatlanmış kodda, bu yöntem yalnızca bir kayıt KIMLIĞI kabul etti:

public async Task<ActionResult> DeleteConfirmed(int id)

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

public async Task<ActionResult> Delete(Department department)

Ayrıca DeleteConfirmed eylem yöntemi adını Deleteolarak değiştirdiniz. HttpPost Delete yöntemi adlı scafkatmış kod, HttpPost yöntemine benzersiz bir imza vermek DeleteConfirmed. (CLR aşırı yüklenmiş yöntemlerin farklı yöntem parametrelerine sahip olmasını gerektirir.) İmzalar benzersiz olduğuna göre, MVC kuralını seçebilir ve HttpPost ve HttpGet silme yöntemleri için aynı adı kullanabilirsiniz.

Bir eşzamanlılık hatası yakalanmışsa, kod silme onayı sayfasını yeniden görüntüler ve bir eşzamanlılık hata mesajı görüntülemesi gerektiğini belirten bir bayrak sağlar.

Views\Department\Delete.cshtml' de, scafkatlama kodunu, 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 h2 ve h3 başlıkları arasına bir hata iletisi ekler:

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

Administrator alanındaki FullName LastName değiştirir:

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

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

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

Departmanlar Dizin sayfasını çalıştırın. Ingilizce departman için Sil köprüsünü sağ tıklayın ve Yeni sekmede aç ' ı seçin ve ardından ilk sekmede İngilizce departman için düzenleme 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 şu anda veritabanında olan ile yenilenir.

Department_Delete_confirmation_page_with_concurrency_error

Yeniden Sil ' e tıklarsanız, departmanın silindiğini gösteren dizin sayfasına yönlendirilirsiniz.

Kodu alma

Tamamlanmış projeyi indir

Ek kaynaklar

Diğer Entity Framework kaynaklarına bağlantılar ASP.NET Data Access-önerilen kaynaklardabulunabilir.

Çeşitli eşzamanlılık senaryolarını işlemenin diğer yolları hakkında bilgi için bkz. Iyimser eşzamanlılık desenleri ve MSDN 'de özellik değerleriyle çalışma . Sonraki öğreticide, Instructor ve Student varlıkları için bir hiyerarşi başına tablo devralmanın nasıl uygulanacağı gösterilmektedir.

Sonraki adımlar

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

  • Eşzamanlılık çakışmaları hakkında öğrenildi
  • İyimser eşzamanlılık eklendi
  • Değiştirilen departman denetleyicisi
  • Test edilen eşzamanlılık işleme
  • Silme sayfası güncelleştirildi

Veri modelinde devralmayı nasıl uygulayacağınızı öğrenmek için sonraki makaleye ilerleyin.