HOW TO:在儲存變更時執行商務邏輯 (Entity Framework)
Entity Framework 可讓您將變更儲存到資料庫之前,先執行自訂商務邏輯。 在處理 SaveChanges 作業之前,會先引發 SavingChanges 事件。 處理這個事件可在將變更儲存到資料庫之前,先實作自訂商務邏輯。 從 .NET Framework 4 版開始,SaveChanges 方法就是 virtual。 這表示您可以直接覆寫此方法,而不是訂閱 SavingChanges 事件。
本主題的範例會示範如何覆寫 SaveChanges 方法及處理 SavingChanges 事件,以便在這些變更保存到資料庫之前先驗證物件內容中的已變更物件。
本主題的範例是根據 Adventure Works Sales Model。 若要執行此範例中的程式碼,您必須已經將 AdventureWorks Sales Model 加入到專案中,並設定您的專案使用 Entity Framework 。 若要這樣做,請完成 HOW TO:手動設定 Entity Framework 專案和 HOW TO:手動定義模型和對應檔 (Entity Framework) 中的程序。
第一個範例顯示如何覆寫自訂物件內容類別中的 SaveChanges 方法。 第二個範例示範如何使用 OnContextCreated 在 ObjectContext 的執行個體中註冊 SavingChanges 事件的處理常式。 第三個範例示範如何在衍生自 ObjectContext 的 Proxy 類別中處理此事件。 第四個範例示範使用來自第二個範例的 Proxy 類別對物件進行變更,然後呼叫 SaveChanges 的程式碼。
範例
在此範例中會覆寫 SaveChanges 方法,讓您驗證具有 Added 或 Modified EntityState 的物件。 此範例是根據 HOW TO:定義自訂物件內容 (Entity Framework) 中所定義之自訂物件內容。
Public Overloads Overrides Function SaveChanges(ByVal options As SaveOptions) As Integer
For Each entry As ObjectStateEntry In ObjectStateManager.GetObjectStateEntries(EntityState.Added Or EntityState.Modified)
' Validate the objects in the Added and Modified state
' if the validation fails throw an exeption.
Next
Return MyBase.SaveChanges(options)
End Function
public override int SaveChanges(SaveOptions options)
{
foreach (ObjectStateEntry entry in
ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Modified))
{
// Validate the objects in the Added and Modified state
// if the validation fails throw an exeption.
}
return base.SaveChanges(options);
}
在此範例中,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 Shared Sub context_SavingChanges(ByVal sender As Object, ByVal e As EventArgs)
' Validate the state of each entity in the context
' before SaveChanges can succeed.
For Each entry As ObjectStateEntry In DirectCast(sender, ObjectContext).ObjectStateManager.GetObjectStateEntries(EntityState.Added Or EntityState.Modified)
' Find an object state entry for a SalesOrderHeader object.
If Not entry.IsRelationship AndAlso (entry.Entity.GetType() Is GetType(SalesOrderHeader)) Then
Dim orderToCheck As SalesOrderHeader = TryCast(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 ArgumentException(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 ArgumentException(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 context As New AdventureWorksProxy()
' Get the first order from the context.
Dim order As SalesOrderHeader = context.Context.SalesOrderHeaders.First()
' Add some text that we want to catch before saving changes.
order.Comment = "some text"
Try
' Save changes using the proxy class.
Dim changes As Integer = context.Context.SaveChanges()
Catch ex As InvalidOperationException
' Handle the exception returned by the proxy class
' validation if a problem string is found.
Console.WriteLine(ex.ToString())
// Create an instance of the proxy class that returns an object context.
AdventureWorksProxy context = new AdventureWorksProxy();
// Get the first order from the context.
SalesOrderHeader order =
context.Context.SalesOrderHeaders.First();
// Add some text that we want to catch before saving changes.
order.Comment = "some text";
try
{
// Save changes using the proxy class.
int changes = context.Context.SaveChanges();
}
catch (InvalidOperationException 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 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 = TryCast(sender, ObjectContext)
If context IsNot Nothing 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 AndAlso (entry.Entity.GetType() Is GetType(SalesOrderHeader)) Then
Dim orderToCheck As SalesOrderHeader = TryCast(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 ArgumentException(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 ArgumentException(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"));
}
}
}
}
}
}
另請參閱
工作
HOW TO:在物件狀態變更時執行商務邏輯
HOW TO:在純量屬性變更期間執行商務邏輯 (Entity Framework)
HOW TO:在關聯變更期間執行商務邏輯