Zpracování souběžnosti s Rozhraním Entity Framework 4.0 ve webové aplikaci ASP.NET 4
Tato série kurzů vychází z webové aplikace Contoso University vytvořené Začínáme s řadou kurzů Entity Framework 4.0. Pokud jste nedokončí předchozí kurzy, můžete si jako výchozí bod pro tento kurz stáhnout aplikaci , kterou jste vytvořili. Můžete si také stáhnout aplikaci vytvořenou kompletní řadou kurzů. Pokud máte dotazy k kurzům, můžete je publikovat na fóru ASP.NET Entity Framework.
V předchozím kurzu jste zjistili, jak řadit a filtrovat data pomocí ObjectDataSource
ovládacího prvku a Entity Frameworku. Tento kurz ukazuje možnosti pro zpracování souběžnosti ve ASP.NET webové aplikaci, která používá Entity Framework. Vytvoříte novou webovou stránku, která je vyhrazená k aktualizaci přiřazení v kanceláři instruktora. Problémy se souběžností budete řešit na této stránce a na stránce Oddělení, kterou jste vytvořili dříve.
Konflikty souběžnosti
Ke konfliktu souběžnosti dochází, když jeden uživatel upraví záznam a jiný upraví stejný záznam před zápisem změny prvního uživatele do databáze. Pokud entity Framework nenastavíte tak, aby takové konflikty detekoval, ten, kdo naposledy aktualizuje databázi, přepíše změny jiného uživatele. V mnoha aplikacích je toto riziko přijatelné a nemusíte aplikaci konfigurovat tak, aby zvládala možné konflikty souběžnosti. (Pokud existuje jen málo uživatelů nebo málo aktualizací nebo pokud nejsou skutečně kritické, pokud jsou některé změny přepsány, náklady na programování za souběžnost můžou převážit výhody.) Pokud se nemusíte starat o konflikty souběžnosti, můžete tento kurz přeskočit. zbývající dva kurzy v této sérii nezávisí na ničem, co vytvoříte v tomto.
Pesimistická souběžnost (zamyká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 aktualizacím. Pokud uzamknete řádek pro přístup k aktualizacím, žádní jiní uživatelé nebudou moct zamknout řádek jen pro čtení nebo pro přístup k aktualizacím, protože by získali kopii dat, která se právě mění. Pokud řádek uzamknete 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á určité nevýhody. Může být složité programovat. Vyžaduje významné prostředky pro správu databází a může způsobovat problémy s výkonem, když se zvýší počet uživatelů aplikace (to znamená, že se dobře škáluje). Z těchto důvodů pesimistická souběžnost nepodporují všechny systémy pro správu databází. Entity Framework neposkytuje žádnou integrovanou podporu a tento kurz neukazuje, jak ho implementovat.
Optimistická metoda souběžného zpracování
Alternativou k pesimistické souběžnosti je optimistická souběžnost. Optimistická souběžnost znamená, že povolíte, aby ke konfliktům souběžnosti docházelo, a pokud ano, pak odpovídajícím způsobem reagovat. Jan například spustí stránku Department.aspx , klikne na odkaz Upravit pro oddělení Historie a sníží částku rozpočtu z 1 000 000 USD na 125 000,00 USD. (John spravuje konkurenční oddělení a chce uvolnit peníze pro své vlastní oddělení.)
Než Jan klikne na Aktualizovat, Jana spustí stejnou stránku, klikne na odkaz Upravit pro oddělení Historie a potom změní pole Počáteční datum z 10. 1. 2011 na 1. 1. 1999. (Jane spravuje oddělení historie a chce mu dát vyšší úroveň.)
Jan nejdřív klikne na Aktualizovat a pak na Aktualizovat. Jane v prohlížeči teď uvádí částku rozpočtu jako 1 000 000,00 USD, ale není to správné, protože jan změnil částku na 125 000,00 USD.
Mezi akce, které můžete v tomto scénáři provést, patří:
Můžete sledovat, kterou vlastnost uživatel změnil, a aktualizovat pouze odpovídající sloupce v databázi. V ukázkovém scénáři by nedošlo ke ztrátě dat, protože dva uživatelé aktualizovali různé vlastnosti. Až někdo příště projde oddělení historie, uvidí 1. 1. 1999 a 125 000,00 USD.
Toto je výchozí chování v Entity Frameworku a může výrazně snížit počet konfliktů, které by mohly vést ke ztrátě dat. Toto chování ale nevyhne ztrátě dat, pokud se u stejné vlastnosti entity provedou konkurenční změny. Kromě toho, toto chování není vždy možné; při mapování uložených procedur na typ entity se při provedení jakýchkoli změn entity v databázi aktualizují všechny vlastnosti entity.
Můžete nechat Janovu změnu přepsat. Jakmile Jane klikne na Aktualizovat, částka rozpočtu se vrátí na 1 000 000,00 USD. Tento scénář 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.)
V databázi můžete zabránit, aby se změny Jane aktualizovaly. Obvykle byste zobrazili chybovou zprávu, zobrazili byste jí aktuální stav dat a povolili jí znovu zadat změny, pokud je bude chtít provést. Proces můžete dále automatizovat tak, že uložíte její vstup a poskytnete jí možnost ho znovu použít, aniž byste ho museli znovu zadávat. Tento scénář se nazývá Store Wins . (Hodnoty úložiště dat mají přednost před hodnotami odeslanými klientem.)
Zjišťování konfliktů souběžnosti
V Entity Frameworku můžete konflikty vyřešit zpracováním OptimisticConcurrencyException
výjimek, které Entity Framework vyvolá. Aby bylo možné zjistit, kdy tyto výjimky vyvolat, musí být Rozhraní Entity Framework schopné detekovat konflikty. Proto musíte odpovídajícím způsobem nakonfigurovat databázi a datový model. Mezi možnosti povolení detekce konfliktů patří:
V databázi zahrňte sloupec tabulky, pomocí kterého můžete určit, kdy byl řádek změněn. Pak můžete nakonfigurovat Entity Framework tak, aby zahrnoval tento sloupec do klauzule
Where
SQLUpdate
neboDelete
příkazů.To je účel
Timestamp
sloupce v tabulceOfficeAssignment
.Datový typ sloupce se
Timestamp
také nazýváTimestamp
. Sloupec ale ve skutečnosti neobsahuje hodnotu data nebo času. Místo toho je hodnota pořadové číslo, které se při každé aktualizaci řádku zvýší.Update
V příkazu neboDelete
klauzuleWhere
obsahuje původníTimestamp
hodnotu. Pokud aktualizovaný řádek změnil jiný uživatel, hodnota vTimestamp
souboru se liší od původní hodnoty, takžeWhere
klauzule nevrátí žádný řádek, který by se měl aktualizovat. Když Entity Framework zjistí, že aktuálníUpdate
neboDelete
příkaz neaktualizoval žádné řádky (to znamená, že počet ovlivněných řádků je nulový), interpretuje to jako konflikt souběžnosti.Nakonfigurujte Entity Framework tak, aby zahrnoval původní hodnoty všech sloupců v tabulce v klauzuli
Where
Update
aDelete
příkazů.Stejně jako u první možnosti platí, že pokud se od prvního přečtení řádku něco na řádku změnilo,
Where
klauzule nevrátí řádek, který se má aktualizovat, což Entity Framework interpretuje jako konflikt souběžnosti. Tato metoda je stejně efektivní jako použitíTimestamp
pole, ale může být neefektivní. U databázových tabulek, které mají mnoho sloupců, to může vést k velmi velkýmWhere
klauzulemi a ve webové aplikaci může vyžadovat udržování velkých objemů stavu. Udržování velkých objemů stavu může ovlivnit výkon aplikace, protože buď vyžaduje prostředky serveru (například stav relace), nebo musí být součástí samotné webové stránky (například stav zobrazení).
V tomto kurzu přidáte zpracování chyb pro konflikty optimistické souběžnosti pro entitu, která nemá vlastnost sledování (entitu Department
), a pro entitu, která má vlastnost sledování (entitu OfficeAssignment
).
Zpracování optimistické souběžnosti bez vlastnosti sledování
Pokud chcete implementovat optimistickou souběžnost pro entitu Department
, která nemá vlastnost sledování (Timestamp
), provedete následující úlohy:
- Změňte datový model tak, aby umožňoval sledování souběžnosti pro
Department
entity. SchoolRepository
Ve třídě zpracovávat výjimky souběžnosti vSaveChanges
metodě.- Na stránce Departments.aspx můžete zpracovávat výjimky souběžnosti zobrazením zprávy uživateli s upozorněním, že pokusy o změny byly neúspěšné. Uživatel pak může zobrazit aktuální hodnoty a zkusit změny zopakovat, pokud jsou ještě potřeba.
Povolení sledování souběžnosti v datovém modelu
V sadě Visual Studio otevřete webovou aplikaci Contoso University, se kterou jste pracovali v předchozím kurzu v této sérii.
Otevřete SchoolModel.edmx a v návrháři datového modelu klikněte pravým tlačítkem na Name
vlastnost v entitě Department
a potom klikněte na Vlastnosti. V okně Vlastnosti změňte vlastnost na ConcurrencyMode
Fixed
.
To samé udělejte pro ostatní skalární vlastnosti bez primárního klíče (Budget
, StartDate
a Administrator
.) (U navigačních vlastností to nejde udělat.) To určuje, že pokaždé, když Entity Framework vygeneruje Update
příkaz nebo Delete
SQL pro aktualizaci Department
entity v databázi, musí být tyto sloupce (s původními hodnotami) zahrnuty do klauzule Where
. Pokud se při Update
spuštění příkazu nebo Delete
nenajde žádný řádek, Entity Framework vyvolá výjimku optimistické souběžnosti.
Uložte a zavřete datový model.
Zpracování výjimek souběžnosti v dal
Otevřete Soubor SchoolRepository.cs a přidejte následující using
příkaz pro System.Data
obor názvů:
using System.Data;
Přidejte následující novou SaveChanges
metodu, která zpracovává výjimky optimistické souběžnosti:
public void SaveChanges()
{
try
{
context.SaveChanges();
}
catch (OptimisticConcurrencyException ocex)
{
context.Refresh(RefreshMode.StoreWins, ocex.StateEntries[0].Entity);
throw ocex;
}
}
Pokud při zavolání této metody dojde k chybě souběžnosti, nahradí se hodnoty vlastností entity v paměti hodnotami, které jsou aktuálně v databázi. Výjimka souběžnosti se opakuje, aby ji webová stránka zvládla.
DeleteDepartment
V metodách a UpdateDepartment
nahraďte stávající volání context.SaveChanges()
volánímSaveChanges()
, aby bylo možné vyvolat novou metodu.
Zpracování výjimek souběžnosti v prezentační vrstvě
Otevřete Departments.aspx a přidejte OnDeleted="DepartmentsObjectDataSource_Deleted"
do DepartmentsObjectDataSource
ovládacího prvku atribut. Značka otevření ovládacího prvku teď bude vypadat podobně jako v následujícím příkladu.
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.BLL.SchoolBL" DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartmentsByName" DeleteMethod="DeleteDepartment" UpdateMethod="UpdateDepartment"
ConflictDetection="CompareAllValues" OldValuesParameterFormatString="orig{0}"
OnUpdated="DepartmentsObjectDataSource_Updated" SortParameterName="sortExpression"
OnDeleted="DepartmentsObjectDataSource_Deleted" >
V ovládacím DepartmentsGridView
prvku zadejte všechny sloupce tabulky v atributu DataKeyNames
, jak je znázorněno v následujícím příkladu. Všimněte si, že se tím vytvoří velmi velká pole stavu zobrazení, což je jeden z důvodů, proč je obecně upřednostňovaným způsobem sledování konfliktů souběžnosti použití pole sledování.
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource"
DataKeyNames="DepartmentID,Name,Budget,StartDate,Administrator"
OnRowUpdating="DepartmentsGridView_RowUpdating"
OnRowDataBound="DepartmentsGridView_RowDataBound"
AllowSorting="True" >
Otevřete Departments.aspx.cs a přidejte následující using
příkaz pro System.Data
obor názvů:
using System.Data;
Přidejte následující novou metodu, kterou budete volat z obslužných rutin ovládacího prvku Updated
zdroje dat a Deleted
obslužných rutin událostí pro zpracování výjimek souběžnosti:
private void CheckForOptimisticConcurrencyException(ObjectDataSourceStatusEventArgs e, string function)
{
if (e.Exception.InnerException is OptimisticConcurrencyException)
{
var concurrencyExceptionValidator = new CustomValidator();
concurrencyExceptionValidator.IsValid = false;
concurrencyExceptionValidator.ErrorMessage =
"The record you attempted to edit or delete was modified by another " +
"user after you got the original value. The edit or delete operation was canceled " +
"and the other user's values have been displayed so you can " +
"determine whether you still want to edit or delete this record.";
Page.Validators.Add(concurrencyExceptionValidator);
e.ExceptionHandled = true;
}
}
Tento kód kontroluje typ výjimky, a pokud se jedná o výjimku souběžnosti, kód dynamicky vytvoří CustomValidator
ovládací prvek, který následně zobrazí zprávu v ovládacím ValidationSummary
prvku.
Volejte novou metodu z obslužné rutiny Updated
události, kterou jste přidali dříve. Kromě toho vytvořte novou Deleted
obslužnou rutinu události, která volá stejnou metodu (ale nedělá nic jiného):
protected void DepartmentsObjectDataSource_Updated(object sender, ObjectDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
CheckForOptimisticConcurrencyException(e, "update");
// ...
}
}
protected void DepartmentsObjectDataSource_Deleted(object sender, ObjectDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
CheckForOptimisticConcurrencyException(e, "delete");
}
}
Testování optimistické souběžnosti na stránce Oddělení
Spusťte stránku Departments.aspx .
Klikněte na Upravit na řádku a změňte hodnotu ve sloupci Rozpočet . (Nezapomeňte, že můžete upravovat jenom záznamy, které jste vytvořili pro účely tohoto kurzu, protože existující School
databázové záznamy obsahují některá neplatná data. Záznam ekonomického oddělení je bezpečným záznamem pro experimentování.)
Otevřete nové okno prohlížeče a spusťte stránku znovu (zkopírujte adresu URL z pole adresy prvního okna prohlížeče do druhého okna prohlížeče).
Klikněte na Upravit na stejném řádku, který jste upravili dříve, a změňte hodnotu Rozpočet na něco jiného.
V druhém okně prohlížeče klikněte na Aktualizovat. Částka rozpočtu se úspěšně změnila na tuto novou hodnotu.
V prvním okně prohlížeče klikněte na Aktualizovat. Aktualizace se nezdaří. Částka rozpočtu se znovu zobrazí pomocí hodnoty, kterou jste nastavili v druhém okně prohlížeče, a zobrazí se chybová zpráva.
Zpracování optimistické souběžnosti pomocí vlastnosti sledování
Pokud chcete zpracovat optimistickou souběžnost entity s vlastností sledování, provedete následující úlohy:
- Přidejte do datového modelu uložené procedury pro správu
OfficeAssignment
entit. (Vlastnosti sledování a uložené procedury se nemusí používat společně, jsou tady jenom seskupené pro ilustraci.) - Přidejte metody CRUD do DAL a BLL pro
OfficeAssignment
entity, včetně kódu pro zpracování výjimek optimistické souběžnosti v DAL. - Vytvořte webovou stránku přiřazení office.
- Otestujte optimistickou souběžnost na nové webové stránce.
Přidání uložených procedur OfficeAssignment do datového modelu
Otevřete soubor SchoolModel.edmx v návrháři modelu, klikněte pravým tlačítkem na návrhovou plochu a klikněte na Aktualizovat model z databáze. Na kartě Přidat v dialogovém okně Zvolte databázové objekty rozbalte uložené procedury , vyberte tři OfficeAssignment
uložené procedury (viz následující snímek obrazovky) a potom klikněte na Dokončit. (Tyto uložené procedury již byly v databázi, když jste ji stáhli nebo vytvořili pomocí skriptu.)
Klikněte pravým tlačítkem na entitu OfficeAssignment
a vyberte Mapování uložené procedury.
Nastavte funkce Insert, Update a Delete tak, aby používaly odpovídající uložené procedury. OrigTimestamp
Jako parametr Update
funkce nastavte Vlastnost na Timestamp
a vyberte možnost Použít původní hodnotu.
Když Entity Framework zavolá uloženou proceduru UpdateOfficeAssignment
, předá původní hodnotu Timestamp
sloupce v parametru OrigTimestamp
. Uložená procedura používá ve své Where
klauzuli tento parametr:
ALTER PROCEDURE [dbo].[UpdateOfficeAssignment]
@InstructorID int,
@Location nvarchar(50),
@OrigTimestamp timestamp
AS
UPDATE OfficeAssignment SET Location=@Location
WHERE InstructorID=@InstructorID AND [Timestamp]=@OrigTimestamp;
IF @@ROWCOUNT > 0
BEGIN
SELECT [Timestamp] FROM OfficeAssignment
WHERE InstructorID=@InstructorID;
END
Uložená procedura také vybere novou hodnotu Timestamp
sloupce po aktualizaci, aby Entity Framework mohl udržovat entitu OfficeAssignment
, která je v paměti, synchronizovaná s odpovídajícím řádkem databáze.
(Všimněte si, že uložená procedura pro odstranění přiřazení office nemá OrigTimestamp
parametr. Z tohoto důvodu entity Framework nemůže před odstraněním ověřit, jestli se entita nezměnila.)
Uložte a zavřete datový model.
Přidání metod OfficeAssignment do dal
Otevřete soubor ISchoolRepository.cs a přidejte následující metody CRUD pro OfficeAssignment
sadu entit:
IEnumerable<OfficeAssignment> GetOfficeAssignments(string sortExpression);
void InsertOfficeAssignment(OfficeAssignment OfficeAssignment);
void DeleteOfficeAssignment(OfficeAssignment OfficeAssignment);
void UpdateOfficeAssignment(OfficeAssignment OfficeAssignment, OfficeAssignment origOfficeAssignment);
Do souboru SchoolRepository.cs přidejte následující nové metody. UpdateOfficeAssignment
V metodě voláte místní SaveChanges
metodu místo context.SaveChanges
metody .
public IEnumerable<OfficeAssignment> GetOfficeAssignments(string sortExpression)
{
return new ObjectQuery<OfficeAssignment>("SELECT VALUE o FROM OfficeAssignments AS o", context).Include("Person").OrderBy("it." + sortExpression).ToList();
}
public void InsertOfficeAssignment(OfficeAssignment officeAssignment)
{
context.OfficeAssignments.AddObject(officeAssignment);
context.SaveChanges();
}
public void DeleteOfficeAssignment(OfficeAssignment officeAssignment)
{
context.OfficeAssignments.Attach(officeAssignment);
context.OfficeAssignments.DeleteObject(officeAssignment);
context.SaveChanges();
}
public void UpdateOfficeAssignment(OfficeAssignment officeAssignment, OfficeAssignment origOfficeAssignment)
{
context.OfficeAssignments.Attach(origOfficeAssignment);
context.ApplyCurrentValues("OfficeAssignments", officeAssignment);
SaveChanges();
}
V testovacím projektu otevřete Soubor MockSchoolRepository.cs a přidejte do něj následující OfficeAssignment
kolekci a metody CRUD. (Napodobené úložiště musí implementovat rozhraní úložiště, jinak se řešení nezkompiluje.)
List<OfficeAssignment> officeAssignments = new List<OfficeAssignment>();
public IEnumerable<OfficeAssignment> GetOfficeAssignments(string sortExpression)
{
return officeAssignments;
}
public void InsertOfficeAssignment(OfficeAssignment officeAssignment)
{
officeAssignments.Add(officeAssignment);
}
public void DeleteOfficeAssignment(OfficeAssignment officeAssignment)
{
officeAssignments.Remove(officeAssignment);
}
public void UpdateOfficeAssignment(OfficeAssignment officeAssignment, OfficeAssignment origOfficeAssignment)
{
officeAssignments.Remove(origOfficeAssignment);
officeAssignments.Add(officeAssignment);
}
Přidání metod přiřazení OfficeAs do BLL
V hlavním projektu otevřete Soubor SchoolBL.cs a přidejte následující metody CRUD pro entitu nastavenou OfficeAssignment
do něj:
public IEnumerable<OfficeAssignment> GetOfficeAssignments(string sortExpression)
{
if (string.IsNullOrEmpty(sortExpression)) sortExpression = "Person.LastName";
return schoolRepository.GetOfficeAssignments(sortExpression);
}
public void InsertOfficeAssignment(OfficeAssignment officeAssignment)
{
try
{
schoolRepository.InsertOfficeAssignment(officeAssignment);
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
public void DeleteOfficeAssignment(OfficeAssignment officeAssignment)
{
try
{
schoolRepository.DeleteOfficeAssignment(officeAssignment);
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
public void UpdateOfficeAssignment(OfficeAssignment officeAssignment, OfficeAssignment origOfficeAssignment)
{
try
{
schoolRepository.UpdateOfficeAssignment(officeAssignment, origOfficeAssignment);
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
Vytvoření webové stránky OfficeAssignments
Vytvořte novou webovou stránku, která používá stránku předlohy Site.Master a pojmenujte ji OfficeAssignments.aspx. Do ovládacího prvku s Content
názvem Content2
přidejte následující kód :
<h2>Office Assignments</h2>
<asp:ObjectDataSource ID="OfficeAssignmentsObjectDataSource" runat="server" TypeName="ContosoUniversity.BLL.SchoolBL"
DataObjectTypeName="ContosoUniversity.DAL.OfficeAssignment" SelectMethod="GetOfficeAssignments"
DeleteMethod="DeleteOfficeAssignment" UpdateMethod="UpdateOfficeAssignment" ConflictDetection="CompareAllValues"
OldValuesParameterFormatString="orig{0}"
SortParameterName="sortExpression" OnUpdated="OfficeAssignmentsObjectDataSource_Updated">
</asp:ObjectDataSource>
<asp:ValidationSummary ID="OfficeAssignmentsValidationSummary" runat="server" ShowSummary="true"
DisplayMode="BulletList" Style="color: Red; width: 40em;" />
<asp:GridView ID="OfficeAssignmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="OfficeAssignmentsObjectDataSource" DataKeyNames="InstructorID,Timestamp"
AllowSorting="True">
<Columns>
<asp:CommandField ShowEditButton="True" ShowDeleteButton="True" ItemStyle-VerticalAlign="Top">
<ItemStyle VerticalAlign="Top"></ItemStyle>
</asp:CommandField>
<asp:TemplateField HeaderText="Instructor" SortExpression="Person.LastName">
<ItemTemplate>
<asp:Label ID="InstructorLastNameLabel" runat="server" Text='<%# Eval("Person.LastName") %>'></asp:Label>,
<asp:Label ID="InstructorFirstNameLabel" runat="server" Text='<%# Eval("Person.FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:DynamicField DataField="Location" HeaderText="Location" SortExpression="Location"/>
</Columns>
<SelectedRowStyle BackColor="LightGray"></SelectedRowStyle>
</asp:GridView>
Všimněte si, že v atributu DataKeyNames
kód určuje Timestamp
vlastnost a klíč záznamu (InstructorID
). Zadání vlastností v atributu DataKeyNames
způsobí, že ovládací prvek je uloží ve stavu ovládacího prvku (který je podobný stavu zobrazení), aby byly původní hodnoty k dispozici během zpracování zpětného zpracování.
Pokud jste hodnotu neuložili Timestamp
, Entity Framework ji nebude mít pro Where
klauzuli příkazu SQL Update
. V důsledku toho by se nenašlo nic, co by bylo možné aktualizovat. V důsledku toho entity Framework vyvolá při každé OfficeAssignment
aktualizaci entity výjimku optimistické souběžnosti.
Otevřete OfficeAssignments.aspx.cs a přidejte následující using
příkaz pro vrstvu přístupu k datům:
using ContosoUniversity.DAL;
Přidejte následující Page_Init
metodu, která povolí funkci dynamických dat. Přidejte také následující obslužnou rutinu ObjectDataSource
pro událost ovládacího prvku Updated
, abyste mohli zkontrolovat chyby souběžnosti:
protected void Page_Init(object sender, EventArgs e)
{
OfficeAssignmentsGridView.EnableDynamicData(typeof(OfficeAssignment));
}
protected void OfficeAssignmentsObjectDataSource_Updated(object sender, ObjectDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
var concurrencyExceptionValidator = new CustomValidator();
concurrencyExceptionValidator.IsValid = false;
concurrencyExceptionValidator.ErrorMessage = "The record you attempted to " +
"update has been modified by another user since you last visited this page. " +
"Your update was canceled to allow you to review the other user's " +
"changes and determine if you still want to update this record.";
Page.Validators.Add(concurrencyExceptionValidator);
e.ExceptionHandled = true;
}
}
Testování optimistické souběžnosti na stránce OfficeAssignments
Spusťte stránku OfficeAssignments.aspx .
Klikněte na Upravit v řádku a změňte hodnotu ve sloupci Umístění .
Otevřete nové okno prohlížeče a spusťte stránku znovu (zkopírujte adresu URL z prvního okna prohlížeče do druhého okna prohlížeče).
Klikněte na Upravit na stejném řádku, který jste upravili dříve, a změňte hodnotu Umístění na něco jiného.
V druhém okně prohlížeče klikněte na Aktualizovat.
Přepněte do prvního okna prohlížeče a klikněte na Aktualizovat.
Zobrazí se chybová zpráva a hodnota Umístění byla aktualizována tak, aby zobrazovala hodnotu, na kterou jste ji změnili v druhém okně prohlížeče.
Zpracování souběžnosti pomocí ovládacího prvku EntityDataSource
Ovládací EntityDataSource
prvek obsahuje integrovanou logiku, která rozpoznává nastavení souběžnosti v datovém modelu a odpovídajícím způsobem zpracovává operace aktualizace a odstranění. Stejně jako u všech výjimek je však nutné zpracovávat OptimisticConcurrencyException
výjimky sami, abyste mohli poskytnout uživatelsky přívětivou chybovou zprávu.
Dále nakonfigurujete stránku Courses.aspx (která používá EntityDataSource
ovládací prvek) tak, aby umožňovala operace aktualizace a odstranění a zobrazila chybovou zprávu, pokud dojde ke konfliktu souběžnosti. Entita Course
nemá sloupec sledování souběžnosti, takže použijete stejnou metodu, jakou jste použili s entitou Department
: sledujte hodnoty všech vlastností, které nejsou klíčové.
Otevřete soubor SchoolModel.edmx . Pro jiné než klíčové vlastnosti Course
entity (Title
, Credits
a DepartmentID
) nastavte vlastnost Režim souběžnosti na Fixed
hodnotu . Pak datový model uložte a zavřete.
Otevřete stránku Courses.aspx a proveďte následující změny:
V ovládacím
CoursesEntityDataSource
prvku přidejteEnableUpdate="true"
atributy aEnableDelete="true"
. Počáteční značka pro tento ovládací prvek se teď podobá následujícímu příkladu:<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="false" AutoGenerateWhereClause="True" EntitySetName="Courses" EnableUpdate="true" EnableDelete="true">
V ovládacím
CoursesGridView
prvku změňte hodnotu atributuDataKeyNames
na"CourseID,Title,Credits,DepartmentID"
. Pak do elementuCommandField
Columns
přidejte prvek, který zobrazuje tlačítka Upravit a Odstranit (<asp:CommandField ShowEditButton="True" ShowDeleteButton="True" />
). OvládacíGridView
prvek se teď podobá následujícímu příkladu:<asp:GridView ID="CoursesGridView" runat="server" AutoGenerateColumns="False" DataKeyNames="CourseID,Title,Credits,DepartmentID" DataSourceID="CoursesEntityDataSource" > <Columns> <asp:CommandField ShowEditButton="True" ShowDeleteButton="True" /> <asp:BoundField DataField="CourseID" HeaderText="CourseID" ReadOnly="True" SortExpression="CourseID" /> <asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" /> <asp:BoundField DataField="Credits" HeaderText="Credits" SortExpression="Credits" /> </Columns> </asp:GridView>
Spusťte stránku a vytvořte konfliktní situaci jako předtím na stránce Oddělení. Spusťte stránku ve dvou oknech prohlížeče, klikněte na Upravit na stejném řádku v každém okně a proveďte v každém z nich jinou změnu. V jednom okně klikněte na Aktualizovat a v druhém okně klikněte na Aktualizovat . Když kliknete na Aktualizovat podruhé, zobrazí se chybová stránka, která je výsledkem neošetřené výjimky souběžnosti.
Tuto chybu zpracujete velmi podobným způsobem, jakým jste ji zpracovali u ObjectDataSource
ovládacího prvku. Otevřete stránku Courses.aspx a v ovládacím CoursesEntityDataSource
prvku zadejte obslužné rutiny pro Deleted
události a Updated
. Počáteční značka ovládacího prvku teď vypadá podobně jako v následujícím příkladu:
<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="false"
AutoGenerateWhereClause="true" EntitySetName="Courses"
EnableUpdate="true" EnableDelete="true"
OnDeleted="CoursesEntityDataSource_Deleted"
OnUpdated="CoursesEntityDataSource_Updated">
Před ovládací CoursesGridView
prvek přidejte následující ValidationSummary
ovládací prvek:
<asp:ValidationSummary ID="CoursesValidationSummary" runat="server"
ShowSummary="true" DisplayMode="BulletList" />
V Courses.aspx.cs přidejte using
příkaz pro System.Data
obor názvů, přidejte metodu, která kontroluje výjimky souběžnosti, a přidejte obslužné rutiny pro EntityDataSource
ovládací prvek Updated
a Deleted
obslužné rutiny. Kód bude vypadat takto:
using System.Data;
protected void CoursesEntityDataSource_Updated(object sender, EntityDataSourceChangedEventArgs e)
{
CheckForOptimisticConcurrencyException(e, "update");
}
protected void CoursesEntityDataSource_Deleted(object sender, EntityDataSourceChangedEventArgs e)
{
CheckForOptimisticConcurrencyException(e, "delete");
}
private void CheckForOptimisticConcurrencyException(EntityDataSourceChangedEventArgs e, string function)
{
if (e.Exception != null && e.Exception is OptimisticConcurrencyException)
{
var concurrencyExceptionValidator = new CustomValidator();
concurrencyExceptionValidator.IsValid = false;
concurrencyExceptionValidator.ErrorMessage =
"The record you attempted to edit or delete was modified by another " +
"user after you got the original value. The edit or delete operation was canceled " +
"and the other user's values have been displayed so you can " +
"determine whether you still want to edit or delete this record.";
Page.Validators.Add(concurrencyExceptionValidator);
e.ExceptionHandled = true;
}
}
Jediným rozdílem mezi tímto kódem a tím, co jste udělali pro ObjectDataSource
ovládací prvek, je, že v tomto případě je výjimka souběžnosti ve Exception
vlastnosti objektu argumentů události, nikoli ve vlastnosti této výjimky InnerException
.
Spusťte stránku a znovu vytvořte konflikt souběžnosti. Tentokrát se zobrazí chybová zpráva:
Tím se dokončí úvod do zpracování konfliktů souběžnosti. Další kurz poskytne pokyny ke zlepšení výkonu ve webové aplikaci, která používá Entity Framework.