如何:在保存更改时执行业务逻辑(实体框架)
使用 实体框架 可以在将更改保存到数据库之前执行自定义业务逻辑。SavingChanges 事件在处理 SaveChanges 操作之前引发。处理该事件可以在将更改保存到数据库之前实现自定义业务逻辑。有关如何实现自定义业务逻辑的更多信息,请参见自定义对象(实体框架)。本主题中的示例演示如何处理 SavingChanges 事件,以在将这些更改永久保存到数据库之前验证对象上下文中已更改的对象。
本主题中的示例基于 Adventure Works 销售模型。若要运行本示例中的代码,必须已将 AdventureWorks 销售模型添加到您的项目中,并将项目配置为使用 实体框架。为此,请完成如何:手动配置实体框架项目和如何:手动定义实体数据模型(实体框架) 中的过程。
第一个示例演示如何使用 OnContextCreated 为 ObjectContext 的实例中的 SavingChanges 事件注册处理程序。第二个示例演示如何在从 ObjectContext 派生的代理类中处理此事件。第三个示例演示的代码使用第二个示例中的代理类对对象进行更改,然后调用 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 派生的代理类中对对象进行更改,然后调用 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"));
}
}
}
}
}
}