共用方式為


加入、修改和刪除物件 (Entity Framework)

物件內容中的物件是表示資料來源中資料之實體類型的執行個體 (Instance)。您可以修改、建立及刪除物件內容中的物件,而物件服務會追蹤對這些物件所做的變更。當呼叫 SaveChanges 方法時,物件服務會產生及執行一些命令,這些命令會對資料來源執行同等的插入、更新或刪除陳述式 (Statement)。如需詳細資訊,請參閱儲存變更及管理並行 (Entity Framework)

舉例來說,假設您執行一個查詢,傳回 SalesOrderHeader 物件和相關 SalesOrderDetail 物件的集合。您可以列舉此集合,並執行以下作業:

  • 變更訂單的 ShipDate 屬性。

  • 呼叫 DeleteObject 方法來刪除特定的項目。

  • 呼叫 Add 方法來將產品項目加入至訂單。

  • 呼叫物件內容上的 SaveChanges 方法來將物件的變更儲存回資料來源。

下列範例顯示物件內容中對物件所做的各種變更:

Dim order As SalesOrderHeader = _
context.SalesOrderHeader.Where( _
        "it.SalesOrderID = @id", New ObjectParameter( _
         "id", orderId)).First()

' Change the status and ship date of an existing order.
order.Status = 1
order.ShipDate = DateAndTime.Today

' Load items for the order, if not already loaded.
If Not order.SalesOrderDetail.IsLoaded Then
    order.SalesOrderDetail.Load()
End If

' Delete the first item in the order.
context.DeleteObject(order.SalesOrderDetail.First())

' Create a new item using the static Create method
' and add it to the order.
order.SalesOrderDetail.Add( _
    SalesOrderDetail.CreateSalesOrderDetail( _
    1, 0, 2, 750, 1, CDec(2171.2942), 0, 0, Guid.NewGuid(), _
    DateAndTime.Today))

' Save changes in the object context to the database.
Dim changes As Integer = context.SaveChanges()
SalesOrderHeader order =
    context.SalesOrderHeader.Where
    ("it.SalesOrderID = @id", new ObjectParameter(
     "id", orderId)).First();

// Change the status and ship date of an existing order.
order.Status = 1;
order.ShipDate = DateTime.Today;

// Load items for the order, if not already loaded.
if (!order.SalesOrderDetail.IsLoaded)
{
    order.SalesOrderDetail.Load();
}

// Delete the first item in the order.
context.DeleteObject(order.SalesOrderDetail.First());

// Create a new item using the static Create method 
// and add it to the order.
order.SalesOrderDetail.Add(
    SalesOrderDetail.CreateSalesOrderDetail(0,
    0, 2, 750, 1, (decimal)2171.2942, 0, 0,
    Guid.NewGuid(), DateTime.Today));

// Save changes in the object context to the database.
int changes = context.SaveChanges();

加入物件

當您要在資料來源中插入資料時,必須建立實體類型的執行個體,並且將物件加入至物件內容。您必須先設定所有不支援 null 值的屬性,才能加入新的物件。請考慮使用實體類型的靜態 CreateObjectName 方法,建立實體類型的新執行個體。實體資料模型 工具在產生實體類型時會在每個類別中都包含這個方法。這個建立方法是用來建立物件的執行個體,並設定不可為 null 之類別的所有屬性。這個方法會針對 CSDL 檔案中已套用 Nullable="false" 屬性 (Attribute) 的每個屬性 (Property) 都包含參數。

下列範例會使用靜態 CreateSalesOrderHeader 方法建立 SalesOrderHeader 類別的新執行個體。

' Create a new SalesOrderHeader using the static 
' CreateSalesOrderHeader method.
Dim order As SalesOrderHeader = _
    SalesOrderHeader.CreateSalesOrderHeader( _
    1, Convert.ToByte(1), DateTime.Now, DateTime.Today.AddMonths(2), _
    Convert.ToByte(1), False, String.Empty, customer.ContactID, shipMethod, _
    0, 0, 0, 0, Guid.NewGuid(), DateTime.Now)
// Create a new SalesOrderHeader using the static 
// CreateSalesOrderHeader method.
SalesOrderHeader order = SalesOrderHeader.CreateSalesOrderHeader(0,
    Convert.ToByte(1), DateTime.Now, DateTime.Today.AddMonths(2),
    Convert.ToByte(1), false, string.Empty, customer.ContactID, shipMethod, 
    0, 0, 0, 0, Guid.NewGuid(), DateTime.Now);

如需詳細資訊,請參閱 HOW TO:使用靜態 Create 方法建立物件 (Entity Framework)

您可以透過呼叫 AddObject 方法或呼叫具型別 ObjectContext 上的其中一個 AddToEntitySetName 方法,將新的物件加入至物件內容。此外,也可以將物件加入至現有 EntityCollection,藉此將物件加入至物件內容。在已附加至物件內容的 EntityCollection 上呼叫 Add 方法時,所要加入的物件會被加入至相同 ObjectContext。同理,您可以將新的物件執行個體設定到 EntityReferenceValue,藉此加入物件。

導覽屬性會定義物件之間的關聯性。因此,我們建議您當物件與物件內容中的物件相關時,請設定導覽屬性。例如,將新 SalesOrderDetail 物件的 SalesOrderHeader 關聯性屬性設定為此產品項目所屬之訂單的執行個體。當您建立與物件內容中另一個物件相關的新物件時,請使用下列其中一種方法來加入此物件:

  • 針對一對多或多對多關聯性,請呼叫 EntityCollection 上的 Add,並指定相關物件。

  • 針對一對一或多對一關聯性,請將 EntityReferenceValue 屬性設定到相關物件。

  • 呼叫 AddObject 方法將新的物件加入至物件內容,然後使用前述的兩個方法定義關聯性。

下列考量適用於加入新物件的情況:

  • 在呼叫 SaveChanges 之前,物件服務會針對每個已使用 AddObject 方法加入的新物件產生暫存的索引鍵值。在呼叫 SaveChanges 之後,當插入新的資料列時,資料來源指派的識別值會取代該索引鍵值。

  • 如果資料庫未產生實體的索引鍵值,您應該指派唯一值。如果兩個物件擁有之使用者指定的關鍵值相同,則當呼叫 SaveChanges 時會發生 InvalidOperationException。如果發生此情況,您應該指派唯一的值,並重試作業。

  • 當您定義物件之間的關聯性並呼叫 SaveChanges 時,實體架構 會自動在資料來源中設定外部索引鍵值。不過,如果實體對應的是執行插入、更新及刪除的預存程序 (Stored Procedure),則不會自動設定外部索引鍵值。在此情況下,您必須為相關物件正確地將對應至外部索引鍵的屬性設定成正確值。如需詳細資訊,請參閱預存程序支援 (Entity Framework)

修改物件

在變更物件的純量、複雜或導覽屬性並呼叫 SaveChanges 時,會把更新傳送至資料來源。您可以藉由變更導覽屬性來變更物件間的關聯性,例如變更 EntityReference 的值,或從 EntityCollection 移除物件。如需詳細資訊,請參閱 HOW TO:變更物件之間的關聯性 (Entity Framework)

物件服務會使用 IEntityChangeTracker 的執行個體,追蹤對已附加至 ObjectContext 的物件所做之變更。每個被追蹤的物件都有一個 IEntityChangeTracker 的執行個體。除非查詢使用的是將 MergeOption 設為 NoTracking 的方式,否則查詢會傳回處於 Unchanged 狀態的物件。實體資料模型 工具會在實體類型之每個屬性的屬性 setter 中產生對變更追蹤方法的呼叫,如下列範例的 SalesOrderHeader 類別中 Status 屬性的屬性 setter 所示。

Set(ByVal value As Byte)
    Me.OnStatusChanging(value)
    Me.ReportPropertyChanging("Status")
    Me._Status = Global.System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value)
    Me.ReportPropertyChanged("Status")
    Me.OnStatusChanged()
End Set
set
{
    this.OnStatusChanging(value);
    this.ReportPropertyChanging("Status");
    this._Status = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
    this.ReportPropertyChanged("Status");
    this.OnStatusChanged();
}

ReportPropertyChanging 方法和 ReportPropertyChanged 方法會報告 IEntityChangeTracker 的屬性變更。如果您使用自訂資料類別搭配 實體資料模型 (EDM),也應該報告屬性變更,使物件服務能夠進行追蹤。如需詳細資訊,請參閱報告自訂資料類別中的變更 (Entity Framework)

每當呼叫屬性 setter 時,物件的狀態就會從 Unchanged 變更為 Modified。即使當設定的值與目前的值相同時,還是會發生這個動作。在呼叫 AcceptAllChanges 方法之後,狀態會恢復 Unchanged。根據預設,會在 SaveChanges 作業期間呼叫 AcceptAllChanges

實體資料模型 工具也會產生一對部分方法,名稱為 OnPropertyChangingOnPropertyChanged。這兩個方法會在屬性 setter 中被呼叫。請在部分類別中擴充這些方法,以便在屬性變更期間插入自訂商務邏輯。如需詳細資訊,請參閱 HOW TO:在屬性變更期間執行商務邏輯 (Entity Framework)

下列考量適用於修改物件的情況:

  • 當 Complex 物件的任何純量或複雜屬性發生變更時,最上層實體物件的狀態會變更成 Modified

  • 當物件處於 Detached 狀態時,變更不會被追蹤。物件在由使用 NoTracking 合併選項的查詢傳回的時候,或在藉由呼叫 DetachObjectContext 中斷連結之後,會處於這個狀態。

  • 您可以將 EntityReference 值指派至新的物件,藉以變更兩個物件之間的關聯性。在此情況下,當您呼叫 SaveChanges 時,實體架構 會自動在資料來源中更新外部索引鍵值。不過,如果實體對應的是執行插入、更新及刪除的預存程序,則不會自動更新外部索引鍵值。在此情況下,您必須為新的關聯正確地將對應至外部索引鍵的屬性設定成正確值。如需詳細資訊,請參閱預存程序支援 (Entity Framework)

刪除物件

ObjectContext 上呼叫 DeleteObject 方法會為指定的物件加上刪除標記。直到呼叫 SaveChanges 之後,才會從資料來源刪除資料列。

下列考量適用於刪除物件的情況:

  • 刪除物件時,也會一併刪除與其他物件的任何關聯性。

  • 兩個物件的關聯性受條件約束時,刪除父物件也會一併刪除所有子物件。這個結果與在關聯性的關聯上啟用 CascadeDelete 屬性相同。如需詳細資訊,請參閱參考條件約束 (Entity Framework)

  • 由查詢傳回的物件與一個或多個其他物件相關時,該查詢一定會傳回一些有關那些相關物件的資訊,以易於進行刪除物件。在某些情況下,當您嘗試刪除物件時,這項資訊可能會使 UpdateException 發生。例如,當定義關聯性的關聯已經在 Association 的父代 End 中有指定的 <OnDelete Action="Cascade" /> 項目時,您將收到此例外狀況。發生這種問題時,請在呼叫 DeleteObject 方法之前先明確載入相關物件。

  • 您可以為已經刪除的物件再次呼叫 DeleteObject 方法。

如需詳細資訊,請參閱 HOW TO:加入、修改和刪除物件 (Entity Framework)

在特定實體集中建立物件

可能會發生實體類型屬於多個實體集的狀況。例如,假設有一個狀況是資料庫的兩個資料表具有相同的結構描述。如果您想要分割資料來產生更有效率的備份程序,可能會發生這種情況。例如,您可能具有在 CustomerCustomerArchive 資料表之間分割的客戶資料,其中 CustomerArchive 具有的結構描述與 Customer 相同,但是用於六個月以上未下訂單的客戶。Customer 可能每個晚上都會備份,而 CustomerArchive 則只會每週備份。從對應的觀點來看,CustomerCustomerArchive 必須屬於不同的實體集。實體架構 讓實體類型存在於一個或多個實體集之中,藉此支援這個案例。如需詳細資訊,請參閱實體集 (EDM)

當實體類型存在於多個實體集內時,物件服務可讓您將此類型的新執行個體加入特定實體集。若要這麼做,當您呼叫 AddObject 方法將物件加入至物件內容時,必須指定 entitySetName 的值。如需詳細資訊,請參閱 HOW TO:將物件加入特定的實體集 (Entity Framework)

實體資料模型 工具也會在 ObjectContext 上產生 AddToEntitySetName 方法,而對於概念模型中定義的每個實體集都會各有一個方法。這些方法會呼叫 AddObject,並且傳遞特定方法的 EntitySetName 值。請使用這些方法,在特定實體集內加入物件。

另請參閱

工作

HOW TO:使用每個類型的多重實體來定義模型 (Entity Framework)