儲存變更及管理並行存取 (Entity Framework)

Entity Framework 預設會實作開放式並行存取 (Optimistic Concurrency) 模型。 這表示,在查詢資料和更新資料時,資料來源中的資料不會被鎖定。 Entity Framework 會將物件變更儲存到資料庫,而不會檢查是否有並行存取。 針對可能遇到高程度並行存取的實體,我們建議您使用 ConcurrencyMode="fixed" 的屬性 (attribute) 在概念層中定義一個實體屬性 (property),如下列範例所示:

<Property Name="Status" Type="Byte" Nullable="false" ConcurrencyMode="Fixed" />

使用這個屬性時,Entity Framework 會在將變更儲存至資料庫之前,先檢查資料庫是否有變更。 任何衝突的變更都會導致 OptimisticConcurrencyException。 如需詳細資訊,請參閱 HOW TO:管理物件內容中的資料並行存取 (Entity Framework)。 如果您定義使用預存程序的 實體資料模型 來對資料來源進行更新,也會發生 OptimisticConcurrencyException。 在這種情況下,當用來執行更新的預存程序報告並未更新任何資料列時,便會引發例外狀況。

在這類高並行存取案例中進行更新時,我們建議您經常呼叫 Refresh。 當您呼叫 Refresh 時,RefreshMode 會控制變更散佈的方式。 StoreWins 選項將會使得 Entity Framework 使用資料庫中的對應值來覆寫物件快取中的所有資料。 反之,ClientWins 選項會使用資料來源中的最新值來取代快取中的原始值。 如此可確保物件快取中所有已變更的資料都可以順利儲存回資料來源,其方式是消除快取中的資料變更與資料來源中相同資料的變更兩者之間的衝突。

如果對資料來源更新可能會修改屬於此物件內容中其他物件的資料,請在呼叫 SaveChanges 方法之後再呼叫 Refresh 方法。 例如,在 AdventureWorks Sales Model 中加入新的 SalesOrderDetail 時,便會觸發更新 SubTotal 資料行來反映具有新項目的小計。 在這種情況下,請呼叫 Refresh 方法並且傳遞此訂單的 SalesOrderHeader 物件。 這樣可確保將觸發產生的值送回到物件內容中的 SalesOrderHeader 物件。

Entity Framework 會追蹤對快取中的物件所做的變更。 當呼叫 SaveChanges 方法時,Entity Framework 會嘗試將變更合併回資料來源。 當快取中加入了物件或重新整理物件之後,如果物件快取中的資料變更與資料來源中的變更衝突,則 SaveChanges 會失敗,並引發 OptimisticConcurrencyException。 這樣會導致整個交易復原。 當 OptimisticConcurrencyException 發生時,您應該處理它,其方式是呼叫 Refresh,並指定是否應該藉由保留物件資料中的資料 ClientWins 或使用資料來源中的資料更新物件快取 StoreWins,以解決衝突狀況,如下列範例所示:

Try
    ' Try to save changes, which may cause a conflict. 
    Dim num As Integer = context.SaveChanges()
    Console.WriteLine("No conflicts. " & num.ToString() & " updates saved.")
Catch generatedExceptionName As OptimisticConcurrencyException
    ' Resolve the concurrency conflict by refreshing the 
    ' object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders)

    ' Save changes. 
    context.SaveChanges()
    Console.WriteLine("OptimisticConcurrencyException handled and changes saved")
End Try
try
{
    // Try to save changes, which may cause a conflict.
    int num = context.SaveChanges();
    Console.WriteLine("No conflicts. " +
        num.ToString() + " updates saved.");
}
catch (OptimisticConcurrencyException)
{
    // Resolve the concurrency conflict by refreshing the 
    // object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders);

    // Save changes.
    context.SaveChanges();
    Console.WriteLine("OptimisticConcurrencyException "
    + "handled and changes saved");
}

如果無法在資料來源中順利建立加入到 ObjectContext 的物件,SaveChanges 可能會產生 UpdateException。 如果具有關聯性所指定之外部索引鍵的資料列已經存在,就可能發生這種情況。 發生這種情況時,您無法使用 Refresh 來更新物件內容中這個加入的物件。 請改用 MergeOptionOverwriteChanges 值重新載入此物件。

如需有關管理物件內容的詳細資訊,請參閱 HOW TO:管理物件內容中的資料並行存取 (Entity Framework)

您可以選擇使用交易做為開放式並行存取的替代方法。 如需詳細資訊,請參閱管理連接和交易 (Entity Framework)

本節內容

HOW TO:管理物件內容中的資料並行存取 (Entity Framework)

另請參閱

概念

使用物件
建立、加入、修改和刪除物件