HOW TO:在屬性變更期間執行商務邏輯 (Entity Framework)
實體架構 可讓您在變更產生的屬性之前,先執行自訂商務邏輯來執行自訂動作。 實體資料模型 (EDM) 工具會產生代表 EDM 中之實體的資料類別。 雖然不應該針對每一個產生的屬性直接修改這些產生的類別,不過工具也會產生一對名為 OnPropertyChanging 和 OnPropertyChanged 的部分方法,其中 Property 是屬性名稱。 這些方法會在變更屬性的前後由物件服務所呼叫,而且您可以在部分資料類別中擴充這些方法來實作自訂程式碼。 如需如何自訂產生之類別的詳細資訊,請參閱自訂物件 (Entity Framework)。
本主題的範例是根據 Adventure Works Sales Model。 若要執行此範例中的程式碼,您必須已經將 AdventureWorks Sales Model 加入到專案中,並設定您的專案使用 Entity Framework。 若要這樣做,請完成 HOW TO:手動設定 Entity Framework 專案和 HOW TO:以手動方式定義 Entity Data Model (Entity Framework) 中的程序。
若要針對屬性變更實作自訂驗證
在您的專案中,針對每一個要驗證的資料類別定義自訂部分類別。
在此部分類別中,定義下列其中一個或兩個方法,其中 Property 是要驗證的屬性名稱:
OnPropertyChanging - 包含變更發生之前所要執行的程式碼,例如屬性驗證。 value 參數是屬性要變更成的值。 請實作這個方法,在屬性變更發生之前進行驗證。 若要避免變更的進行,您必須擲回例外狀況。
OnPropertyChanged - 包含變更發生之後所要執行的程式碼,例如記錄變更。
範例
這個範例會檢查 SalesOrderHeader.Status 的值,以確定在變更 SalesOrderDetail.OrderQty 之前可以變更訂單,而且暫止的變更會記錄到檔案中。 這個動作會在 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);
}
}
}
}