Как выполнить бизнес-логику при изменении свойств (платформа Entity Framework)
Entity Framework позволяет выполнять собственную пользовательскую бизнес-логику для выполнения пользовательских действий в том случае, если в сформированные свойства были внесены изменения. Средства модели Entity Data Model (модель EDM) формируют классы данных, представляющие сущности в модели EDM. Хотя эти сформированные классы нельзя изменять напрямую, но для каждого из них средства формируют пару разделяемых методов с именами OnСвойствоChanging и OnСвойствоChanged, где Свойство — имя свойства. Данные методы вызываются службами объектов до и после изменения свойства; данные методы можно расширить в разделяемых классах данных для реализации пользовательского кода. Дополнительные сведения о настройках формируемых классов см. в разделе Настройка объектов (платформа Entity Framework).
Пример в этом разделе основан на модели Adventure Works Sales. Чтобы запустить код, используемый в данном примере, нужно сначала добавить к проекту модель AdventureWorks Sales и настроить его для использования платформы Entity Framework. Для этого выполните инструкции из разделов Как вручную настроить проект Entity Framework и Как определить модель EDM вручную (платформа Entity Framework).
Реализация пользовательской проверки изменений свойств
В проекте определите пользовательский разделяемый класс для каждого проверяемого класса данных.
В этом разделяемом классе определите один или оба следующих метода (Свойство — это имя проверяемого свойства):
OnСвойствоChanging — включает код, который будет выполняться перед выполнением изменения, например проверка свойства. Параметр value — это значение, на которое заменяется свойство. Реализуйте данный метод, чтобы выполнять проверку изменения свойства перед его выполнением. Чтобы предотвратить выполнение изменения, следует вызвать исключение.
OnСвойствоChanged — включает код, который будет выполняться после выполнения изменения, например внесение изменения в журнал.
Примеры
В этом примере проверяется значение 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);
}
}
}
}