Procédure : exécuter la logique métier lors de l'enregistrement de modifications (Entity Framework)

Entity Framework vous permet d'exécuter la logique métier personnalisée avant que les modifications ne soient enregistrées dans la base de données. L'événement SavingChanges est déclenché avant exécution d'une opération SaveChanges. Gérez cet événement pour implémenter la logique métier personnalisée avant que les modifications ne soient enregistrées dans la base de données. Pour plus d'informations sur l'implémentation de la logique métier personnalisée, voir Personnalisation des objets (Entity Framework). Les exemples de cette rubrique montrent comment gérer l'événement SavingChanges pour valider les objets modifiés dans un contexte d'objet avant que ces modifications ne soient rendues persistantes dans la base de données.

L'exemple de cette rubrique est basé sur le modèle de vente Adventure Works Sales Model. Pour exécuter le code de cet exemple, vous devez déjà avoir ajouté le modèle de vente AdventureWorks Sales Model à votre projet et configuré ce dernier pour qu'il utilise Entity Framework. Pour ce faire, exécutez les procédures décrites dans Procédure : configurer manuellement un projet Entity Framework et Procédure : définir manuellement un modèle EDM (Entity Data Model) (Entity Framework).

Le premier exemple montre comment utiliser OnContextCreated pour inscrire un gestionnaire pour l'événement SavingChanges dans une instance de ObjectContext. Le deuxième exemple montre comment gérer cet événement dans une classe proxy dérivée de ObjectContext. Le troisième exemple présente du code qui modifie des objets en utilisant la classe proxy du deuxième exemple et qui appelle ensuite SaveChanges.

Exemple

Dans cet exemple, la méthode OnContextCreated est définie comme étant une méthode partielle de AdventureWorksEntities. Le gestionnaire de l'événement SavingChanges est défini dans cette méthode partielle. Le gestionnaire d'événements vérifie que le code appelant n'a pas ajouté de texte inapproprié dans la propriété SalesOrderHeader.Comment avant de rendre les modifications persistantes. Si l'algorithme de vérification de chaîne (non illustré) trouve des problèmes, une exception est levée.

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"));
                    }
                }
            }
        }
}

Dans cet exemple, une instance de la classe AdventureWorksProxy est utilisée pour modifier la propriété Comment d'un objet SalesOrderHeader. Lorsque la méthode SaveChanges est appelée sur l'instance de l'objet ObjectContext fournie par la classe AdventureWorksProxy, le code de validation de l'exemple précédent est exécuté.

' 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());
}

Cet exemple apporte des modifications à des objets de la classe proxy qui est dérivée de ObjectContext et appelle SaveChanges. Cet exemple vise à appeler la gestion d'événements illustrée dans l'exemple précédent.

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"));
                    }
                }
            }
        }
    }
}

Voir aussi

Autres ressources

Utilisation d'objets (Tâches Entity Framework)