Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
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
WhereSQLUpdateneboDeletepříkazů.To je účel
Timestampsloupce v tabulceOfficeAssignment.Datový typ sloupce se
Timestamptaké 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ýší.UpdateV příkazu neboDeleteklauzuleWhereobsahuje původníTimestamphodnotu. Pokud aktualizovaný řádek změnil jiný uživatel, hodnota vTimestampsouboru se liší od původní hodnoty, takžeWhereklauzule nevrátí žádný řádek, který by se měl aktualizovat. Když Entity Framework zjistí, že aktuálníUpdateneboDeletepří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
WhereUpdateaDeletepříkazů.Stejně jako u první možnosti platí, že pokud se od prvního přečtení řádku něco na řádku změnilo,
Whereklauzule nevrátí řádek, který se má aktualizovat, což Entity Framework interpretuje jako konflikt souběžnosti. Tato metoda je stejně efektivní jako použitíTimestamppole, ale může být neefektivní. U databázových tabulek, které mají mnoho sloupců, to může vést k velmi velkýmWhereklauzulemi 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
Departmententity. -
SchoolRepositoryVe třídě zpracovávat výjimky souběžnosti vSaveChangesmetodě. - 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 ConcurrencyModeFixed.
To samé udělejte pro ostatní skalární vlastnosti bez primárního klíče (Budget, StartDatea 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
OfficeAssignmententit. (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
OfficeAssignmententity, 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.SaveChangesmetody .
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 Content2př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, Creditsa DepartmentID) nastavte vlastnost Režim souběžnosti na Fixedhodnotu . 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
CoursesEntityDataSourceprvku 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
CoursesGridViewprvku změňte hodnotu atributuDataKeyNamesna"CourseID,Title,Credits,DepartmentID". Pak do elementuCommandFieldColumnspřidejte prvek, který zobrazuje tlačítka Upravit a Odstranit (<asp:CommandField ShowEditButton="True" ShowDeleteButton="True" />). OvládacíGridViewprvek 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.