Sdílet prostřednictvím


Zpracování souběžnosti s Entity Frameworkem v aplikaci ASP.NET MVC (7 z 10)

Tom Dykstra

Ukázková webová aplikace Contoso University ukazuje, jak vytvářet aplikace ASP.NET MVC 4 pomocí entity Framework 5 Code First a sady Visual Studio 2012. Informace o sérii kurzů najdete v prvním kurzu série.

Poznámka:

Pokud narazíte na problém, který nemůžete vyřešit, stáhněte si dokončenou kapitolu a zkuste problém reprodukovat. Obecně můžete najít řešení problému porovnáním kódu s dokončeným kódem. Informace o některých běžných chybách a jejich řešení najdete v tématu Chyby a alternativní řešení.

V předchozích dvou kurzech jste pracovali se souvisejícími daty. V tomto kurzu se dozvíte, jak zpracovat souběžnost. Vytvoříte webové stránky, které pracují s entitou Department , a stránky, které upravují a odstraňují Department entity, budou zpracovávat chyby souběžnosti. Následující ilustrace znázorňují stránky Index a Odstranit, včetně některých zpráv, které se zobrazí, pokud dojde ke konfliktu souběžnosti.

Snímek obrazovky se stránkou Oddělení univerzity Contoso před úpravami

Snímek obrazovky se stránkou Univerzity se zprávou, která vysvětluje, že operace je zrušená, protože hodnota byla změněna jiným uživatelem

Konflikty souběžnosti

Ke konfliktu souběžnosti dojde, když jeden uživatel zobrazí data entity, aby je mohl upravit, a pak jiný uživatel aktualizuje data stejné entity před zápisem změny prvního uživatele do databáze. Pokud nepovolíte detekci takových konfliktů, každý, kdo aktualizuje databázi, naposledy přepíše změny jiného uživatele. V mnoha aplikacích je toto riziko přijatelné: pokud existuje několik uživatelů nebo několik aktualizací, nebo pokud není ve skutečnosti důležité, pokud jsou některé změny přepsány, náklady na programování pro souběžnost můžou výhodu převažovat. V takovém případě nemusíte aplikaci konfigurovat tak, aby zpracovávala konflikty souběžnosti.

Pesimistické souběžnosti (uzamykání)

Pokud vaše aplikace potřebuje zabránit náhodné ztrátě dat ve scénářích souběžnosti, jedním ze způsobů, jak to udělat, je použít zámky databáze. Tomu se říká pesimistické souběžnost. Například před čtením řádku z databáze si vyžádáte zámek jen pro čtení nebo pro přístup k aktualizaci. Pokud uzamknete řádek pro přístup k aktualizacím, nebudou moct ostatní uživatelé zamknout řádek pro přístup jen pro čtení nebo pro aktualizaci, protože by získali kopii dat, která se právě mění. Pokud uzamknete řádek pro přístup jen pro čtení, ostatní ho můžou také uzamknout pro přístup jen pro čtení, ale ne pro aktualizaci.

Správa zámků má nevýhody. Program může být složitý. Vyžaduje významné prostředky pro správu databází a může způsobit problémy s výkonem při nárůstu počtu uživatelů aplikace (to znamená, že se dobře neššíruje). Z těchto důvodů ne všechny systémy pro správu databází podporují pesimistické souběžnosti. Entity Framework neposkytuje žádnou integrovanou podporu a tento kurz vám neukazuje, jak ji implementovat.

Optimistická metoda souběžného zpracování

Alternativou k pesimistické souběžnosti je optimistická souběžnost. Optimistická souběžnost znamená, že umožňuje, aby došlo ke konfliktům souběžnosti, a pak odpovídajícím způsobem reagovat, pokud ano. Jan například spustí stránku Úpravy oddělení, změní částku rozpočtu pro anglické oddělení z 350 000,00 USD na 0,00 USD.

Changing_English_dept_budget_to_100000

Než Jan klikne na Uložit, jane spustí stejnou stránku a změní pole Počáteční datum od 1. 9. 2007 do 8. 8. 2013.

Changing_English_dept_start_date_to_1999

Jan nejprve klikne na Uložit a uvidí změnu, když se prohlížeč vrátí na stránku Index a pak Jane klikne na Uložit. Co se stane dál, určuje způsob zpracování konfliktů souběžnosti. Mezi tyto možnosti patří:

  • Můžete sledovat, kterou vlastnost uživatel upravil, a aktualizovat pouze odpovídající sloupce v databázi. V ukázkovém scénáři by se neztratila žádná data, protože dva uživatelé aktualizovali různé vlastnosti. Když někdo příště přejde do anglického oddělení, uvidí změny Johna i Janeho – počáteční datum 8. 8. 2013 a rozpočet nula dolarů.

    Tato metoda aktualizace může snížit počet konfliktů, které můžou vést ke ztrátě dat, ale nemůže se vyhnout ztrátě dat, pokud jsou u stejné vlastnosti entity provedeny konkurenční změny. To, jestli Entity Framework funguje tímto způsobem, závisí na tom, jak implementujete aktualizační kód. Často to není praktické ve webové aplikaci, protože může vyžadovat, abyste zachovali velké množství stavu, abyste mohli sledovat všechny původní hodnoty vlastností pro entitu i nové hodnoty. Udržování velkého množství stavu může mít vliv na výkon aplikace, protože vyžaduje prostředky serveru nebo musí být součástí samotné webové stránky (například ve skrytých polích).

  • Janovu změnu můžete nechat přepsat. Když někdo příště přejde do anglického oddělení, uvidí 8.8.2013 a obnovenou hodnotu 350 000,00 USD. To se nazývá klient wins nebo last ve scénáři Wins . (Hodnoty klienta mají přednost před tím, co je v úložišti dat.) Jak je uvedeno v úvodu do této části, pokud neproděláte žádné kódování pro zpracování souběžnosti, dojde k tomu automaticky.

  • V databázi můžete zabránit aktualizaci janovy změny. Obvykle se zobrazí chybová zpráva, zobrazí se její aktuální stav dat a umožníte jí znovu použít její změny, pokud je stále chce provést. Tomu se říká scénář wins ve Storu. (Hodnoty úložiště dat mají přednost před hodnotami odeslanými klientem.) V tomto kurzu implementujete scénář Wins pro Store. Tato metoda zajišťuje, aby se nepřepsaly žádné změny, aniž by uživatel upozorňoval na to, co se děje.

Zjišťování konfliktů souběžnosti

Konflikty můžete vyřešit zpracováním výjimek OptimisticConcurrencyException , které entity Framework vyvolává. Aby bylo možné zjistit, kdy tyto výjimky vyvolat, musí být Entity Framework schopen detekovat konflikty. Proto je nutné správně nakonfigurovat databázi a datový model. Mezi možnosti povolení detekce konfliktů patří:

  • V tabulce databáze zahrňte sledovací sloupec, který lze použít k určení, kdy byl řádek změněn. Potom můžete rozhraní Entity Framework nakonfigurovat tak, aby zahrnovalo tento sloupec v Where klauzuli SQL Update nebo Delete příkazů.

    Datový typ sloupce sledování je obvykle rowversion. Hodnota rowversion je pořadové číslo, které se při každé aktualizaci řádku zvýší. Update V klauzuli nebo Delete příkaz Where obsahuje původní hodnotu sloupce sledování (původní verze řádku). Pokud byl řádek aktualizovaný jiným uživatelem změněn, hodnota ve rowversion sloupci se liší od původní hodnoty, takže příkaz nemůže Delete najít řádek, který Update se má aktualizovat kvůli Where klauzuli. Když Entity Framework zjistí, že žádné řádky nebyly aktualizovány příkazem nebo Delete příkazem Update (to znamená, že počet ovlivněných řádků je nula), interpretuje to jako konflikt souběžnosti.

  • Nakonfigurujte Entity Framework tak, aby zahrnovala původní hodnoty každého sloupce v tabulce v Where klauzuli Update a Delete příkazy.

    Stejně jako v první možnosti, pokud se od prvního čtení řádku něco v řádku změnilo, Where klauzule nevrátí řádek pro aktualizaci, který Entity Framework interpretuje jako konflikt souběžnosti. U databázových tabulek s mnoha sloupci může tento přístup vést k velmi velkým Where klauzulemi a může vyžadovat, abyste zachovali velké množství stavu. Jak už jsme uvedli dříve, udržování velkého množství stavu může ovlivnit výkon aplikace, protože vyžaduje prostředky serveru nebo musí být součástí samotné webové stránky. Tento přístup se proto obecně nedoporučuje a není to metoda použitá v tomto kurzu.

    Pokud chcete tento přístup implementovat ke souběžnosti, je nutné označit všechny vlastnosti jiného než primárního klíče v entitě, pro kterou chcete sledovat souběžnost, přidáním atributu ConcurrencyCheck do nich. Tato změna umožňuje rozhraní Entity Framework zahrnout všechny sloupce do klauzule UPDATE SQL WHERE příkazů.

Ve zbývající části tohoto kurzu přidáte do Department entity vlastnost sledování rowversion, vytvoříte kontroler a zobrazení a otestujete, jestli všechno funguje správně.

Přidání vlastnosti optimistické souběžnosti do entity oddělení

Do pole Models\Department.cs přidejte vlastnost sledování s názvem RowVersion:

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; }
}

Atribut časového razítka určuje, že tento sloupec bude zahrnut do Where klauzule Update a Delete příkazů odesílaných do databáze. Atribut se nazývá Časové razítko, protože předchozí verze SQL Serveru používaly datový typ časového razítka SQL před nahrazením verze řádku SQL. Typ .Net pro rowversion je bajtové pole. Pokud raději používáte rozhraní FLUENT API, můžete pomocí metody IsConcurrencyToken určit vlastnost sledování, jak je znázorněno v následujícím příkladu:

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

Podívejte se na problém GitHubu Replace IsConcurrencyToken by IsRowVersion.

Přidáním vlastnosti, kterou jste změnili model databáze, takže je potřeba provést další migraci. V konzole Správce balíčků (PMC) zadejte následující příkazy:

Add-Migration RowVersion
Update-Database

Vytvoření kontroleru oddělení

Pomocí následujících nastavení vytvořte Department kontroler a zobrazení stejným způsobem jako ostatní kontrolery:

Add_Controller_dialog_box_for_Department_controller

Do pole Controllers\DepartmentController.cs přidejte using příkaz:

using System.Data.Entity.Infrastructure;

Změňte "LastName" na "FullName" všude v tomto souboru (čtyři výskyty), aby rozevírací seznamy správců oddělení obsahovaly celé jméno instruktora, a ne jenom příjmení.

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

Nahraďte stávající kód pro metodu HttpPost Edit následujícím kódem:

[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);
}

Zobrazení uloží původní RowVersion hodnotu do skrytého pole. Když binder modelu vytvoří department instanci, tento objekt bude mít původní RowVersion hodnotu vlastnosti a nové hodnoty pro ostatní vlastnosti, jak zadal uživatel na stránce Upravit. Když pak Entity Framework vytvoří příkaz SQL UPDATE , bude tento příkaz obsahovat WHERE klauzuli, která hledá řádek s původní RowVersion hodnotou.

Pokud příkaz UPDATE neovlivní žádné řádky (žádné řádky nemají původní RowVersion hodnotu), Entity Framework vyvolá DbUpdateConcurrencyException výjimku a kód v catch bloku získá ovlivněnou Department entitu z objektu výjimky. Tato entita má hodnoty načtené z databáze i nové hodnoty zadané uživatelem:

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

Dále kód přidá vlastní chybovou zprávu pro každý sloupec s hodnotami databáze, které se liší od toho, co uživatel zadal na stránce Upravit:

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

Delší chybová zpráva vysvětluje, co se stalo a co s tím dělat:

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.");

Nakonec kód nastaví RowVersion hodnotu objektu Department na novou hodnotu načtenou z databáze. Tato nová RowVersion hodnota se uloží do skrytého pole při opětovném zobrazení stránky Pro úpravy a při příštím kliknutí uživatele na Uložit dojde pouze k chybám souběžnosti, ke kterým dochází, protože se při přehrání stránky Pro úpravy zachytí.

V Views\Department\Edit.cshtml přidejte skryté pole pro uložení RowVersion hodnoty vlastnosti bezprostředně za skryté pole vlastnosti DepartmentID :

@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>

V zobrazení\Department\Index.cshtml nahraďte stávající kód následujícím kódem, kterým přesunete odkazy na řádky doleva a změníte nadpis stránky a záhlaví sloupců tak, aby se zobrazovaly FullName místo LastName ve sloupci Správce :

@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>

Testování optimistického zpracování souběžnosti

Spusťte web a klikněte na Oddělení:

Snímek obrazovky se stránkou Oddělení univerzity Contoso

Klikněte pravým tlačítkem myši na hypertextový odkaz Pro Kim Abercrombie a vyberte Otevřít v nové kartě a potom klikněte na upravit hypertextový odkaz pro Kim Abercrombie. Dvě okna zobrazují stejné informace.

Department_Edit_page_before_changes

Změňte pole v prvním okně prohlížeče a klikněte na Uložit.

Department_Edit_page_1_after_change

V prohlížeči se zobrazí stránka Index se změněnou hodnotou.

Departments_Index_page_after_first_budget_edit

Změňte libovolné pole v druhém okně prohlížeče a klikněte na Uložit.

Department_Edit_page_2_after_change

Klikněte na Uložit v druhém okně prohlížeče. Zobrazí se chybová zpráva:

Snímek obrazovky se stránkou Univerzity s chybovou zprávou, která je připravená pro uživatele, aby znovu vybrali Uložit

Znovu klikněte na Uložit . Hodnota zadaná v druhém prohlížeči se uloží spolu s původní hodnotou dat, která změníte v prvním prohlížeči. Uložené hodnoty se zobrazí, když se zobrazí stránka Index.

Department_Index_page_with_change_from_second_browser

Aktualizace stránky Pro odstranění

U stránky Odstranit služba Entity Framework detekuje konflikty souběžnosti způsobené jiným uživatelem, který upravuje oddělení podobným způsobem. Když metoda HttpGet Delete zobrazí potvrzovací zobrazení, zobrazení obsahuje původní RowVersion hodnotu ve skrytém poli. Tato hodnota je pak k dispozici metodě HttpPost Delete , která se volá, když uživatel potvrdí odstranění. Když Entity Framework vytvoří příkaz SQL DELETE , obsahuje WHERE klauzuli s původní RowVersion hodnotou. Pokud má příkaz za následek nulový dopad na řádky (to znamená, že se řádek po zobrazení stránky potvrzení odstranění změnil), vyvolá se výjimka souběžnosti a HttpGet Delete volá se metoda s příznakem chyby nastaveným na true opětovné zobrazení potvrzovací stránky s chybovou zprávou. Je také možné, že byly ovlivněny nulové řádky, protože řádek odstranil jiný uživatel, takže v takovém případě se zobrazí jiná chybová zpráva.

V DepartmentController.cs nahraďte metodu HttpGet Delete následujícím kódem:

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);
}

Metoda přijímá volitelný parametr, který označuje, zda se stránka znovu zobrazuje po chybě souběžnosti. Pokud je truetento příznak , chybová zpráva se odešle do zobrazení pomocí ViewBag vlastnosti.

Nahraďte kód v HttpPost Delete metodě (pojmenovaný DeleteConfirmed) následujícím kódem:

[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);
    }
}

V vygenerovaný kód, který jste právě nahradili, tato metoda přijala pouze ID záznamu:

public ActionResult DeleteConfirmed(int id)

Tento parametr jste změnili na Department instanci entity vytvořenou pořadačem modelu. Tím získáte přístup k hodnotě RowVersion vlastnosti kromě klíče záznamu.

public ActionResult Delete(Department department)

Změnili jste také název metody akce z DeleteConfirmed na Delete. Vygenerovaný kód pojmenovaný metodou HttpPost Delete DeleteConfirmed HttpPost , který metodě poskytne jedinečný podpis. (CLR vyžaduje přetížené metody, aby měly různé parametry metody.) Teď, když jsou podpisy jedinečné, můžete držet konvence MVC a použít stejný název pro HttpPost metody a HttpGet metody delete.

Pokud dojde k chybě souběžnosti, kód znovu zobrazí potvrzovací stránku odstranění a zobrazí příznak, který označuje, že by se měla zobrazit chybová zpráva souběžnosti.

V views\Department\Delete.cshtml nahraďte vygenerovaný kód následujícím kódem, který provede určité změny formátování a přidá pole chybové zprávy. Změny jsou zvýrazněné.

@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>
}

Tento kód přidá mezi nadpisy chybovou h2 h3 zprávu:

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

LastName Nahradí ho FullName Administrator v poli:

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

Nakonec za příkaz přidá skrytá pole a DepartmentID RowVersion vlastnosti Html.BeginForm :

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

Spusťte stránku Index oddělení. Klikněte pravým tlačítkem myši na odstranit hypertextový odkaz pro anglické oddělení a vyberte Otevřít v novém okně a pak v prvním okně klikněte na upravit hypertextový odkaz pro anglické oddělení.

V prvním okně změňte jednu z hodnot a klikněte na Uložit :

Department_Edit_page_after_change_before_delete

Stránka Index potvrdí změnu.

Departments_Index_page_after_budget_edit_before_delete

V druhém okně klikněte na Odstranit.

Department_Delete_confirmation_page_before_concurrency_error

Zobrazí se chybová zpráva o souběžnosti a hodnoty oddělení se aktualizují s informacemi, které jsou aktuálně v databázi.

Department_Delete_confirmation_page_with_concurrency_error

Pokud znovu kliknete na Odstranit , budete přesměrováni na stránku Index, která ukazuje, že oddělení bylo odstraněno.

Shrnutí

Tím se dokončí úvod ke zpracování konfliktů souběžnosti. Informace o dalších způsobech zpracování různých scénářů souběžnosti najdete v tématu Optimistic concurrency Patterns and Working with Property Values na blogu týmu Entity Framework. V dalším kurzu se dozvíte, jak implementovat dědičnost tabulek podle hierarchie pro entity Instructor a Student entity.

Odkazy na další prostředky Entity Framework najdete v mapě obsahu ASP.NET Data Accessu.