添加、修改和删除对象(实体框架)

对象上下文中的对象是实体类型的实例,表示数据源中的数据。在对象上下文中可以修改、创建和删除对象,对象服务会跟踪对这些对象所做的更改。调用 SaveChanges 方法时,对象服务会生成并执行一些命令,这些命令将对数据源执行等效的插入、更新或删除语句。有关更多信息,请参见保存更改和管理并发(实体框架)

例如,假定执行返回 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);

有关更多信息,请参见如何:使用静态 Create 方法创建对象(实体框架)

通过调用 AddObject 方法或对类型化 ObjectContext 调用一个 AddToEntitySetName 方法,可以将新对象添加到对象上下文。此外,通过将对象添加到现有 EntityCollection,也可以将对象添加到对象上下文。对附加到对象上下文的 EntityCollection 调用 Add 方法时,所添加的对象将添加到该 ObjectContext。同样,通过将新对象实例设置为 EntityReferenceValue,也可以添加对象。

导航属性定义对象之间的关系。如果对象与对象上下文中的其他对象相关,建议设置这些属性。例如,将新 SalesOrderDetail 对象的 SalesOrderHeader 关系属性设置为该行项所属订单的实例。在创建与对象上下文中的另一个对象相关的新对象时,通过使用下列方法之一添加该新对象:

  • 对于一对多或多对多关系,请调用 EntityCollectionAdd 并指定相关对象。

  • 对于一对一或多对一关系,请将 EntityReferenceValue 属性设置为相关对象。

  • 调用 AddObject 方法将新对象添加到对象上下文,然后使用前述两个方法中的一个来定义关系。

在添加新对象时需要考虑下列注意事项:

  • 调用 SaveChanges 之前,对象服务会为使用 AddObject 方法添加的每个新对象分别生成一个临时键值。调用 SaveChanges 后,该键值可能会被插入新行时数据源所指定的标识值所取代。

  • 如果数据源未生成实体的键值,应指定一个唯一值。如果两个对象具有相同的用户指定键值,则在调用 SaveChanges 时会发生 InvalidOperationException。如果发生此问题,应指定唯一值并重试该操作。

  • 在定义对象之间的关系并调用 SaveChanges 时,实体框架 自动设置数据源中的外键值。但是,当实体映射到执行插入、更新和删除的存储过程时,不会自动设置外键值。这种情况下,必须将对应于外键的属性正确设置为相关对象的正确值。有关更多信息,请参见存储过程支持(实体框架)

修改对象

更改对象的标量、复杂或导航属性并调用 SaveChanges 时,更新将发送到数据源。通过更改导航属性(例如更改 EntityReference 的值,或从 EntityCollection 中移除对象),可以更改对象之间的关系,有关更多信息,请参见如何:更改对象间的关系(实体框架)

对象服务使用 IEntityChangeTracker 的实例来跟踪对附加到 ObjectContext 的对象的更改。对于每个被跟踪对象,都有一个 IEntityChangeTracker 实例。除非查询使用设置为 NoTrackingMergeOption,否则查询将返回 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) 中使用自定义数据类,还应报告属性更改以便对象服务能够进行跟踪。有关更多信息,请参见报告自定义数据类中的更改(实体框架)

只要调用属性 setter,对象的状态就会从 Unchanged 更改为 Modified。即使所设置的值与当前值相同也是如此。调用 AcceptAllChanges 方法后,状态将返回为 Unchanged。默认情况下,AcceptAllChanges 是在 SaveChanges 操作过程中调用的。

实体数据模型 工具还生成一对分部方法,分别名为 On属性ChangingOn属性Changed。这些方法是在属性 setter 中调用的。在分部类中扩展这些方法可以在属性更改过程中插入自定义业务逻辑。有关更多信息,请参见如何:在属性更改过程中执行业务逻辑(实体框架)

在修改对象时,应考虑以下注意事项:

  • 更改复杂对象的任何标量或复杂属性后,顶级实体对象的状态将更改为 Modified

  • 当对象处于 Detached 状态时,不会跟踪更改。当对象由使用 NoTracking 合并选项的查询返回,或通过调用 DetachObjectContext 分离后,对象处于此状态。

  • 通过将 EntityReference 值分配给新对象,可以更改两个对象之间的关系。这种情况下,在调用 SaveChanges 时,实体框架 会自动更新数据源中的外键值。但是,当实体映射到执行插入、更新和删除的存储过程时,不会自动更新外键值。这种情况下,必须将对应于外键的属性正确设置为新关系的正确值。有关更多信息,请参见存储过程支持(实体框架)

删除对象

调用 ObjectContextDeleteObject 方法会将指定的对象标记为删除。只有在调用 SaveChanges 之后,才会从数据源中删除该行。

在删除对象时需要考虑下列注意事项:

  • 删除对象时,也将删除与其他对象的所有关系。

  • 当两个对象为约束关系时,删除父对象也会删除所有子对象。此结果与启用关系的关联上的 CascadeDelete 属性相同。有关更多信息,请参见引用约束(实体框架)

  • 如果某个对象是由与一个或多个其他对象相关的查询返回的,则该查询始终返回有关这些相关对象的信息,因此更容易删除对象。某些情况下,在试图删除对象时,此现有信息可能导致发生 UpdateException。例如,当定义关系的关联具有在 Association 的父 End 中指定的 <OnDelete Action="Cascade" /> 元素时,将会接收到此异常。如果出现这种情况,请在调用 DeleteObject 方法之前显式加载相关对象。

  • 可以对已经删除的对象再次调用 DeleteObject 方法。

有关更多信息,请参见如何:添加、修改和删除对象(实体框架)

在特定实体集中创建对象

有时某一实体类型可能属于多个实体集。例如,假设数据库有两个架构相同的表。如果要对数据进行分区以实现更有效的备份过程,就可能出现这种情况。例如,您可能将客户数据在 CustomerCustomerArchive 表之间进行分区,CustomerArchiveCustomer 具有相同的架构,但后一个表用于六个多月还未下订单的客户。Customer 可能每晚备份一次,而 CustomerArchive 只是每周备份一次。从映射的角度来看,CustomerCustomerArchive 必须属于不同的实体集。实体框架 通过允许实体类型存在于一个或多个实体集来支持此方案。有关更多信息,请参见实体集 (EDM)

如果某一实体类型存在于多个实体集中,对象服务允许将该类型的新实例添加到某一特定的实体集中。为此,调用 AddObject 方法将对象添加到对象上下文时,必须指定 entitySetName 的值。有关更多信息,请参见如何:将对象添加到特定实体集(实体框架)

实体数据模型 工具还对 ObjectContext 生成一些 AddToEntitySetName 方法,概念模型中定义的每个实体集都有一个方法。这些方法调用 AddObject 并传递指定方法的 EntitySetName 值。使用这些方法可将对象添加到特定的实体集。

另请参见

任务

如何:通过每种类型多个实体集定义模型(实体框架)