プロパティの変更時にビジネス ロジックを実行する方法 (Entity Framework)
エンティティ フレームワーク では、カスタム ビジネス ロジックを実行することによって、生成されたプロパティが変更されたときにカスタム アクションを実行できます。エンティティ データ モデル (EDM) ツールは、EDM 内のエンティティを表すデータ クラスを生成します。生成されたクラスを直接変更することはできませんが、生成されるプロパティごとに、OnPropertyChanging および OnPropertyChanged という部分メソッドのペアも生成されます (Property はプロパティ名)。これらのメソッドは、プロパティ変更の前後に Object Services によって呼び出されます。これらのメソッドを部分データ クラスで拡張すると、カスタム コードを実装できます。生成されたクラスをカスタマイズする方法の詳細については、「オブジェクトのカスタマイズ (Entity Framework)」を参照してください。
このトピックの例では、Adventure Works Sales Model が使用されています。この例のコードを実行するには、あらかじめプロジェクトに AdventureWorks Sales Model を追加し、Entity Framework が使用されるようにプロジェクトを構成しておく必要があります。具体的な方法については、「Entity Framework プロジェクトを手動で構成する方法」および「Entity Data Model を手動で定義する方法 (Entity Framework)」の手順を参照してください。
プロパティの変更に関するカスタム検証を実装するには
プロジェクトで、検証するデータ クラスごとにカスタム部分クラスを 1 つ定義します。
この部分クラスで、次のメソッドのいずれかまたは両方を定義します。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);
}
}
}
}