HOW TO:在儲存變更時執行商務邏輯 (Entity Framework)
實體架構 可讓您將變更儲存到資料庫之前,先執行自訂商務邏輯。在處理 SaveChanges 作業之前,會先引發 SavingChanges 事件。處理這個事件可在將變更儲存到資料庫之前,先實作自訂商務邏輯。如需如何實作自訂商務邏輯的詳細資訊,請參閱自訂物件 (Entity Framework)。本主題的範例會示範如何處理 SavingChanges 事件,以便在這些變更保存到資料庫之前先驗證物件內容中的已變更物件。
本主題的範例是根據 Adventure Works Sales Model。若要執行此範例中的程式碼,您必須已經將 AdventureWorks Sales Model 加入到專案中,並設定您的專案使用 實體架構。若要這樣做,請完成 HOW TO:手動設定 Entity Framework 專案和 HOW TO:以手動方式定義 Entity Data Model (Entity Framework) 中的程序。
第一個範例示範如何使用 OnContextCreated 在 ObjectContext 的執行個體中註冊 SavingChanges 事件的處理常式。第二個範例示範如何在衍生自 ObjectContext 的 Proxy 類別中處理此事件。第三個範例示範使用來自第二個範例的 Proxy 類別對物件進行變更,然後呼叫 SaveChanges 的程式碼。
範例
在這個範例中,OnContextCreated 方法是定義成 AdventureWorksEntities 的部分方法。SavingChanges 事件的處理常式則是定義在這個部分方法中。這個事件處理常式會確認呼叫的程式碼並未在 SalesOrderHeader.Comment 屬性中加入任何不當文字,然後才會保存變更。如果字串檢查演算法 (這裡未顯示) 找到任何問題,就會引發例外狀況。
Partial Public Class AdventureWorksEntities
Private Sub OnContextCreated()
' Register the handler for the SavingChanges event.
AddHandler Me.SavingChanges, _
AddressOf context_SavingChanges
End Sub
' SavingChanges event handler.
Private Sub context_SavingChanges(ByVal sender As Object, ByVal e As EventArgs)
Dim context As ObjectContext = CType(sender, ObjectContext)
' Validate the state of each entity in the context
' before SaveChanges can succeed.
For Each entry As ObjectStateEntry In _
context.ObjectStateManager.GetObjectStateEntries( _
EntityState.Added Or EntityState.Modified)
' Find an object state entry for a SalesOrderHeader object.
If (Not entry.IsRelationship) And _
(TypeOf entry.Entity Is SalesOrderHeader) Then
Dim orderToCheck As SalesOrderHeader = CType(entry.Entity, SalesOrderHeader)
' Call a helper method that performs string checking
' on the Comment property.
Dim textNotAllowed As String = ValidatorObjectContext.CheckStringForLanguage( _
orderToCheck.Comment)
' If the validation method returns a problem string, raise an error.
If textNotAllowed <> String.Empty Then
Throw New ApplicationException(String.Format("Changes cannot be " _
+ "saved because the {0} '{1}' object contains a " _
+ "string that is not allowed in the property '{2}'.", _
entry.State, "SalesOrderHeader", "Comment"))
End If
End If
Next
End Sub
End Class
public partial class AdventureWorksEntities
{
partial void OnContextCreated()
{
// Register the handler for the SavingChanges event.
this.SavingChanges
+= new EventHandler(context_SavingChanges);
}
// SavingChanges event handler.
private static void context_SavingChanges(object sender, EventArgs e)
{
// Validate the state of each entity in the context
// before SaveChanges can succeed.
foreach (ObjectStateEntry entry in
((ObjectContext)sender).ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Modified))
{
// Find an object state entry for a SalesOrderHeader object.
if (!entry.IsRelationship && (entry.Entity.GetType() == typeof(SalesOrderHeader)))
{
SalesOrderHeader orderToCheck = entry.Entity as SalesOrderHeader;
// Call a helper method that performs string checking
// on the Comment property.
string textNotAllowed = Validator.CheckStringForLanguage(
orderToCheck.Comment);
// If the validation method returns a problem string, raise an error.
if (textNotAllowed != string.Empty)
{
throw new ApplicationException(String.Format("Changes cannot be "
+ "saved because the {0} '{1}' object contains a "
+ "string that is not allowed in the property '{2}'.",
entry.State, "SalesOrderHeader","Comment"));
}
}
}
}
}
在此範例中,AdventureWorksProxy 類別的執行個體是用來變更 SalesOrderHeader 物件的 Comment 屬性。在 AdventureWorksProxy 類別提供的 ObjectContext 執行個體上呼叫 SaveChanges 時,會執行上一個範例中的驗證程式碼。
' Create an instance of the proxy class that returns an object context.
Dim proxy As AdventureWorksProxy = New AdventureWorksProxy()
' Get the first order from the context.
Dim order As SalesOrderHeader = proxy.Context.SalesOrderHeader.First()
' Add some text that we want to catch before saving changes.
order.Comment += "Some inappropriate comment."
Try
' Save changes using the proxy class.
proxy.Context.SaveChanges()
Catch ex As ApplicationException
' Handle the exception returned by the proxy class
' validation if a problem string is found.
Console.WriteLine(ex.ToString())
End Try
// Create an instance of the proxy class that returns an object context.
AdventureWorksProxy proxy = new AdventureWorksProxy();
// Get the first order from the context.
SalesOrderHeader order = proxy.Context.SalesOrderHeader.First();
// Add some text that we want to catch before saving changes.
order.Comment += "Some inappropriate comment.";
try
{
// Save changes using the proxy class.
proxy.Context.SaveChanges();
}
catch (ApplicationException ex)
{
// Handle the exception returned by the proxy class
// validation if a problem string is found.
Console.WriteLine(ex.ToString());
}
此範例會對衍生自 ObjectContext 的 Proxy 類別中的物件進行變更,然後再呼叫 SaveChanges。此範例是用來叫用前面範例中所示範的事件處理。
Public Class AdventureWorksProxy
' Define the object context to be provided.
Private contextProxy As New AdventureWorksEntities()
Public Sub New()
' When the object is initialized, register the
' handler for the SavingChanges event.
AddHandler contextProxy.SavingChanges, _
AddressOf context_SavingChanges
End Sub
' Method that provides an object context.
Public ReadOnly Property Context() As AdventureWorksEntities
Get
Return Me.contextProxy
End Get
End Property
' SavingChanges event handler.
Private Sub context_SavingChanges(ByVal sender As Object, ByVal e As EventArgs)
' Ensure that we are passed an ObjectContext
Dim context As ObjectContext = CType(sender, ObjectContext)
If (Not sender Is Nothing) And (TypeOf sender Is ObjectContext) Then
' Validate the state of each entity in the context
' before SaveChanges can succeed.
For Each entry As ObjectStateEntry In _
context.ObjectStateManager.GetObjectStateEntries( _
EntityState.Added Or EntityState.Modified)
' Find an object state entry for a SalesOrderHeader object.
If (Not entry.IsRelationship) And _
(TypeOf entry.Entity Is SalesOrderHeader) Then
Dim orderToCheck As SalesOrderHeader = CType(entry.Entity, SalesOrderHeader)
' Call a helper method that performs string checking
' on the Comment property.
Dim textNotAllowed As String = Validator.CheckStringForLanguage( _
orderToCheck.Comment)
' If the validation method returns a problem string, raise an error.
If textNotAllowed <> String.Empty Then
Throw New ApplicationException(String.Format("Changes cannot be " _
+ "saved because the {0} '{1}' object contains a " _
+ "string that is not allowed in the property '{2}'.", _
entry.State, "SalesOrderHeader", "Comment"))
End If
End If
Next
End If
End Sub
End Class
public class AdventureWorksProxy
{
// Define the object context to be provided.
private AdventureWorksEntities contextProxy =
new AdventureWorksEntities();
public AdventureWorksProxy()
{
// When the object is initialized, register the
// handler for the SavingChanges event.
contextProxy.SavingChanges
+= new EventHandler(context_SavingChanges);
}
// Method that provides an object context.
public AdventureWorksEntities Context
{
get
{
return contextProxy;
}
}
// SavingChanges event handler.
private void context_SavingChanges(object sender, EventArgs e)
{
// Ensure that we are passed an ObjectContext
ObjectContext context = sender as ObjectContext;
if (context != null)
{
// Validate the state of each entity in the context
// before SaveChanges can succeed.
foreach (ObjectStateEntry entry in
context.ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Modified))
{
// Find an object state entry for a SalesOrderHeader object.
if (!entry.IsRelationship && (entry.Entity.GetType() == typeof(SalesOrderHeader)))
{
SalesOrderHeader orderToCheck = entry.Entity as SalesOrderHeader;
// Call a helper method that performs string checking
// on the Comment property.
string textNotAllowed = Validator.CheckStringForLanguage(
orderToCheck.Comment);
// If the validation method returns a problem string, raise an error.
if (textNotAllowed != string.Empty)
{
throw new ApplicationException(String.Format("Changes cannot be "
+ "saved because the {0} '{1}' object contains a "
+ "string that is not allowed in the property '{2}'.",
entry.State, "SalesOrderHeader","Comment"));
}
}
}
}
}
}