如何:在属性更改过程中执行业务逻辑(实体框架)
实体框架 使您可以在更改已生成属性时执行自己的自定义业务逻辑来执行自定义操作。实体数据模型 (EDM) 工具生成在 EDM 中表示实体的数据类。尽管不应直接修改这些生成的类,但对于每个生成的属性,这些工具还生成一对名为 OnPropertyChanging 和 OnPropertyChanged 的分部方法,其中 Property 为属性名称。对象服务将在属性更改前后分别调用这两个方法,您可以在分部数据类中扩展这些方法来实现自定义代码。有关如何自定义生成的类的更多信息,请参见自定义对象(实体框架)。
本主题中的示例基于 Adventure Works 销售模型。若要运行此示例中的代码,必须已将 AdventureWorks 销售模型添加到您的项目中,并将项目配置为使用 Entity Framework。为此,请完成如何:手动配置实体框架项目和如何:手动定义实体数据模型(实体框架) 中的过程。
为属性更改实现自定义验证
在项目中,为要验证的每个数据类定义自定义分部类。
在此分部类中,定义下面两个方法或其中之一,其中 Property 为要验证的属性的名称:
OnPropertyChanging - 包含在更改发生前要执行的代码,如属性验证。value 参数为该属性将更改到的值。实现此方法可在更改发生前验证属性更改。要阻止更改,必须引发异常。
OnPropertyChanged - 包含在更改发生后要执行的代码,如记录更改。
示例
本示例在更改 SalesOrderDetail.OrderQty 之前检查 SalesOrderHeader.Status 的值以确保订单可以更改,并将挂起更改记录至文件。此操作在 OnOrderQtyChanging 分部方法中执行。如不能进行更改,则引发异常。成功完成更改后,SalesOrderHeader.Status 的值将重置为 1,并记录已完成的更改。这些操作在 OnOrderQtyChanged 分部方法中执行。
Partial Public Class SalesOrderDetail
Inherits EntityObject
Private Sub OnOrderQtyChanging(ByVal value As Short)
' Only handle this change for existing SalesOrderHeader
' objects that are attached to an object context. If the item
' is detached then we cannot access or load the related order.
If EntityState <> EntityState.Detached Then
Try
' Ensure that the referenced SalesOrderHeader is loaded.
If Not SalesOrderHeaderReference.IsLoaded Then
SalesOrderHeaderReference.Load()
End If
Dim order As SalesOrderHeader = SalesOrderHeader
' Cancel the change if the order cannot be modified.
If SalesOrderHeader.Status > 3 Then
Throw New ApplicationException("The quantity cannot be changed " _
+ "or the item cannot be added because the order has either " _
+ "already been shipped or has been cancelled.")
End If
' Log the pending order change.
File.AppendAllText(LogFile, "Quantity of item '" _
+ SalesOrderDetailID.ToString() + "' in order '" _
+ order.SalesOrderID.ToString() _
+ "' changing from '" + OrderQty.ToString() _
+ "' to '" + value.ToString() + "'." + Environment.NewLine _
+ "Change made by user: " + Environment.UserName _
+ Environment.NewLine)
Catch ex As InvalidOperationException
Throw New ApplicationException("The quantity could not be changed " _
+ " because the order information could not be retrieved. " _
+ "The following error occurred:" + ex.Message)
End Try
End If
End Sub
Private Sub OnOrderQtyChanged()
' Only handle this change for existing SalesOrderHeader
' objects that are attached to an object context.
If EntityState <> EntityState.Detached Then
Try
' Ensure that the SalesOrderDetail is loaded.
If Not SalesOrderHeaderReference.IsLoaded Then
SalesOrderHeaderReference.Load()
End If
' Reset the status for the order related to this item.
SalesOrderHeader.Status = 1
' Log the completed order change.
File.AppendAllText(LogFile, "Quantity of item '" _
+ SalesOrderDetailID.ToString() + "' in order '" _
+ SalesOrderHeader.SalesOrderID.ToString() _
+ "' successfully changed to '" + OrderQty.ToString() _
+ "'." + Environment.NewLine _
+ "Change made by user: " + Environment.UserName _
+ Environment.NewLine)
Catch ex As InvalidOperationException
Throw New ApplicationException("An error occurred " _
+ "the data could be in an inconsistent state. " _
+ Environment.NewLine + ex.Message)
End Try
End If
End Sub
End Class
public partial class SalesOrderDetail : EntityObject
{
partial void OnOrderQtyChanging(short value)
{
// Only handle this change for existing SalesOrderHeader
// objects that are attached to an object context. If the item
// is detached then we cannot access or load the related order.
if (EntityState != EntityState.Detached)
{
try
{
// Ensure that the referenced SalesOrderHeader is loaded.
if (!this.SalesOrderHeaderReference.IsLoaded)
{
this.SalesOrderHeaderReference.Load();
}
// Cancel the change if the order cannot be modified.
if (this.SalesOrderHeader.Status > 3)
{
throw new ApplicationException("The quantity cannot be changed "
+ "or the item cannot be added because the order has either "
+ "already been shipped or has been cancelled.");
}
// Log the pending order change.
File.AppendAllText(LogFile, "Quantity of item '"
+ this.SalesOrderDetailID.ToString() + "' in order '"
+ this.SalesOrderHeader.SalesOrderID.ToString()
+ "' changing from '" + this.OrderQty.ToString()
+ "' to '" + value.ToString() + "'." + Environment.NewLine
+ "Change made by user: " + Environment.UserName
+ Environment.NewLine);
}
catch (InvalidOperationException ex)
{
throw new ApplicationException("The quantity could not be changed "
+ " because the order information could not be retrieved. "
+ "The following error occurred:" + ex.Message);
}
}
}
partial void OnOrderQtyChanged()
{
// Only handle this change for existing SalesOrderHeader
// objects that are attached to an object context.
if (EntityState != EntityState.Detached)
{
try
{
// Ensure that the SalesOrderDetail is loaded.
if (!SalesOrderHeaderReference.IsLoaded)
{
SalesOrderHeaderReference.Load();
}
// Reset the status for the order related to this item.
this.SalesOrderHeader.Status = 1;
// Log the completed order change.
File.AppendAllText(LogFile, "Quantity of item '"
+ SalesOrderDetailID.ToString() + "' in order '"
+ SalesOrderHeader.SalesOrderID.ToString()
+ "' successfully changed to '" + OrderQty.ToString()
+ "'." + Environment.NewLine
+ "Change made by user: " + Environment.UserName
+ Environment.NewLine);
}
catch (InvalidOperationException ex)
{
throw new ApplicationException("An error occurred; "
+ "the data could be in an inconsistent state. "
+ Environment.NewLine + ex.Message);
}
}
}
}