Как выполнить бизнес-логику при изменении скалярных свойств (платформа Entity Framework)

Entity Framework позволяет выполнять собственную пользовательскую бизнес-логику для выполнения пользовательских действий в том случае, если в сформированные свойства были внесены изменения. Средства модели модель EDM (сущностная модель данных) формируют классы данных, представляющие сущности в концептуальной модели. Хотя эти сформированные классы нельзя изменять напрямую, но для каждого из них средства формируют пару разделяемых методов с именами OnСвойствоChanging и OnСвойствоChanged, где Свойство — имя свойства. Эти методы вызываются Entity Framework до и после изменения свойства. Чтобы реализовать пользовательский код, их можно расширить в разделяемых классах данных.

Cc716747.note(ru-ru,VS.100).gifПримечание
Если код уровня объектов был сформирован при помощи текстового шаблона, отличного от текстового шаблона по умолчанию, то разделяемые методы, возможно, не были сформированы.

Пример в этом разделе основан на модели Adventure Works Sales. Чтобы запустить код из данного примера, нужно сначала добавить к проекту модель AdventureWorks Sales и настроить его для использования платформы Entity Framework. Для этого выполните инструкции из разделов Как вручную настроить проект Entity Framework и Как определить модель и файлы сопоставления вручную (платформа Entity Framework).

Реализация пользовательской проверки изменений свойств

  1. В проекте определите пользовательский разделяемый класс для каждого проверяемого класса данных.

  2. В этом разделяемом классе определите один или оба следующих метода (Свойство — это имя проверяемого свойства):

    • 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 Me.SalesOrderHeaderReference.IsLoaded Then
                    Me.SalesOrderHeaderReference.Load()
                End If

                ' Cancel the change if the order cannot be modified. 
                If Me.SalesOrderHeader.Status > 3 Then
                    Throw New InvalidOperationException("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 '" & _
                    Me.SalesOrderDetailID.ToString() & "' in order '" & _
                    Me.SalesOrderHeader.SalesOrderID.ToString() & _
                    "' changing from '" + Me.OrderQty.ToString() & _
                    "' to '" & value.ToString() + "'." & Environment.NewLine & _
                    "Change made by user: " & Environment.UserName & _
                    Environment.NewLine)
            Catch ex As InvalidOperationException
                Throw New InvalidOperationException(("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. 
                Me.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 InvalidOperationException(("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 InvalidOperationException("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 InvalidOperationException("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 InvalidOperationException("An error occurred; "
                + "the data could be in an inconsistent state. "
                + Environment.NewLine + ex.Message);
            }
        }
    }
}

См. также

Задачи

Как выполнять бизнес-логику при изменении состояния объекта
Как обеспечить выполнение бизнес-логики при изменении ассоциаций
Как выполнять правила бизнес-логики при сохранении изменений (платформа Entity Framework)

Другие ресурсы

Entity Data Model Tools