Share via


Procédure pas à pas : mappage d'une entité aux procédures stockées (Entity Data Model Tools)

Cette rubrique montre comment utiliser ADO.NET Entity Data Model Designer (Concepteur d'entités) pour mapper les opérations d'insertion, de mise à jour et de suppression d'un type d'entité à des procédures stockées. Les opérations d'insertion, de mise à jour et de suppression d'un type d'entité peuvent utiliser des instructions SQL qui sont générées automatiquement par le système (valeur par défaut), ou utiliser des procédures stockées qui sont spécifiées par le développeur. Le code d'application que vous utilisez pour créer, mettre à jour et supprimer des entités est le même, que vous utilisiez ou non des procédures stockées pour mettre à jour la base de données.

Dans cette procédure pas à pas, vous allez mapper deux types d'entités (dans le modèle conceptuel) à des procédures stockées (dans le modèle de stockage) en modifiant le fichier .edmx utilisé dans l'application CourseManager (pour plus d'informations, consultez la section Composants requis, plus loin dans cette rubrique). Vous allez également écrire du code qui insérera, mettra à jour et supprimera des types d'entités.

Cc716679.note(fr-fr,VS.100).gifRemarque :
Si vous ne mappez pas les trois opérations d'insertion, de mise à jour ou de suppression d'un type d'entité aux procédures stockées, les opérations non mappées échouent au moment de l'exécution et une UpdateException est levée.

Configuration requise

Pour effectuer cette procédure pas à pas, vous devez générer l'application CourseManager. Pour plus d'informations et d'instructions, consultez le Démarrage rapide d'Entity Framework. Après avoir créé cette application, vous allez modifier son fichier .edmx en mappant deux types d'entités à des procédures stockées.

Cc716679.note(fr-fr,VS.100).gifRemarque :
Étant donné qu'un grand nombre des rubriques de procédure pas à pas de cette documentation utilisent l'application CourseManager comme point de départ, nous vous recommandons d'utiliser une copie de l'application CourseManager pour cette procédure pas à pas, plutôt que de modifier le code CourseManager d'origine.

Cette procédure pas à pas suppose que le lecteur a des compétences de base avec Visual Studio, le .NET Framework et la programmation en Visual C# ou en Visual Basic.

Mappage de l'entité Person à des procédures stockées

Lorsque vous mappez l'opération d'insertion d'une entité à une procédure stockée, si le serveur crée la valeur de clé primaire pour la ligne insérée, vous devez mapper à nouveau cette valeur à la propriété de clé de l'entité. Dans cet exemple, la procédure stockée InsertPerson retourne la clé primaire nouvellement créée en tant que partie intégrante du jeu de résultats de la procédure stockée. La clé primaire est mappée à la clé d'entité (PersonID) à l'aide de la fonctionnalité <Ajouter un Result Binding> du Concepteur d'entités.

Cc716679.note(fr-fr,VS.100).gifRemarque :
Si vous mappez une opération d'insertion, de mise à jour ou de suppression à une procédure stockée qui retourne un paramètre de sortie avec une valeur entière, la case à cocher Paramètre des lignes affectées est activée.Si la case à cocher est sélectionnée pour un paramètre et que la valeur retournée est zéro lorsque l'opération est appelée, une OptimisticConcurrencyException est levée.

Pour mapper l'entité Person à des procédures stockées

  1. Ouvrez la solution CourseManager dans Visual Studio.

  2. Dans l'Explorateur de solutions, double-cliquez sur le fichier School.edmx.

    Le fichier School.edmx s'ouvre dans ADO.NET Entity Data Model Designer (Concepteur d'entités).

  3. Cliquez avec le bouton droit sur le type d'entité Person, puis sélectionnez Mappage de procédure stockée.

    Les mappages de procédures stockées apparaissent dans la fenêtre Détails de mappage.

  4. Cliquez sur <Sélectionner un Insert Function>.

    Le champ devient une liste déroulante des procédures stockées dans le modèle de stockage qui peut être mappé aux types d'entité dans le modèle conceptuel.

  5. Sélectionnez InsertPerson dans la liste déroulante.

    Les mappages par défaut entre les paramètres des procédures stockées et les propriétés d'entité apparaissent. Notez que les flèches indiquent le sens du mappage : les valeurs des propriétés sont fournies aux paramètres des procédures stockées.

  6. Cliquez sur <Ajouter un Result Binding>.

    Le champ devient modifiable.

  7. Tapez NewPersonID, le nom du paramètre retourné par la procédure stockée InsertPerson. Appuyez sur Entrée.

    Par défaut, NewPersonID est mappé à la clé d'entité PersonID. Notez qu'une flèche indique le sens du mappage : la valeur de la colonne de résultats est fournie à la propriété.

  8. Cliquez sur <Sélectionner un Update Function>, puis sélectionnez UpdatePerson dans la liste déroulante résultante.

    Les mappages par défaut entre les paramètres des procédures stockées et les propriétés d'entité apparaissent.

  9. Cliquez sur <Sélectionner un Delete Function>, puis sélectionnez DeletePerson dans la liste déroulante résultante.

    Les mappages par défaut entre les paramètres des procédures stockées et les propriétés d'entité apparaissent.

Les opérations d'insertion, de mise à jour et de suppression du type d'entité Person sont maintenant mappées à des procédures stockées.

Mappage de l'entité OfficeAssignment à des procédures stockées

Dans cet exemple, nous mappons le type d'entité OfficeAssignment aux procédures stockées. Dans ce mappage, nous utilisons l'option Utiliser Original Value sur l'opération de mise à jour pour activer un moyen pratique de vérifier le contrôle concurrentiel dans notre code d'application.

Pour mapper l'entité OfficeAssignment à des procédures stockées

  1. Cliquez avec le bouton droit sur le type d'entité OfficeAssignment, puis sélectionnez Stored Procedure Mapping.

    Les mappages de procédures stockées apparaissent dans la fenêtre Détails de mappage.

  2. Cliquez sur <Sélectionner un Insert Function>, puis sélectionnez InsertOfficeAssignment dans la liste déroulante résultante.

    Les mappages par défaut entre les paramètres des procédures stockées et les propriétés d'entité apparaissent.

  3. Cliquez sur <Ajouter un Result Binding>.

    Le champ devient modifiable.

  4. Tapez Timestamp.

  5. Cliquez sur le champ vide dans la colonne Property/Value en regard de Timestamp.

    Le champ devient une liste déroulante des propriétés auxquelles nous pouvons mapper la valeur qui est retournée par la procédure stockée InsertOfficeAssignment.

  6. Sélectionnez Timestamp dans la liste déroulante.

  7. Cliquez sur <Sélectionner un Update Function>, puis sélectionnez UpdateOfficeAssignment dans la liste déroulante résultante.

    Les mappages par défaut entre les paramètres des procédures stockées et les propriétés d'entité apparaissent. Des cases à cocher apparaissent dans la colonne Utiliser Original Value en regard de chaque propriété mappée.

  8. Cliquez sur le champ vide dans la colonne Propriété qui correspond au paramètre OrigTimestamp, puis sélectionnez Timestamp dans la liste déroulante résultante.

    Le Concepteur d'entités n'a pas fait de ce mappage le mappage par défaut car le nom du paramètre ne correspondait pas exactement au nom de la propriété.

  9. Activez, dans la colonne Utiliser Original Value, la case qui correspond à la propriété Timestamp.

    En cas de tentative de mise à jour, la valeur de la propriété Timestamp, qui a été initialement lue dans la base de données, sera utilisée lors de la réécriture de données à la base de données. Si la valeur ne correspond pas à la valeur de la base de données, une exception OptimisticConcurrencyException sera levée.

  10. Cliquez sur <Ajouter un Result Binding>.

    Le champ devient modifiable.

  11. Remplacez <Ajouter un Result Binding> par Timestamp.

  12. Cliquez sur le champ vide dans la colonne Property/Value en regard de Timestamp.

    Le champ devient une liste déroulante des propriétés auxquelles nous pouvons mapper la colonne de résultats qui est retournée par la procédure stockée UpdateOfficeAssignment.

  13. Sélectionnez Timestamp dans la liste déroulante.

  14. Cliquez sur <Sélectionner un Delete Function>, puis sélectionnez DeleteOfficeAssignment dans la liste déroulante résultante.

    Les mappages par défaut entre les paramètres des procédures stockées et les propriétés d'entité apparaissent.

Les opérations d'insertion, de mise à jour et de suppression du type d'entité OfficeAssignment sont maintenant mappées à des procédures stockées.

Création de l'interface utilisateur

Ensuite, vous allez ajouter deux formulaires à l'application CourseManager. Un formulaire fournit une interface permettant d'afficher et de mettre à jour les informations relatives aux enseignants. L'autre formulaire fournit une interface permettant d'afficher et de mettre à jour les attributions des lieux de travail.

Pour créer l'interface utilisateur

  1. Cliquez avec le bouton droit sur le projet CourseManager dans l'Explorateur de solutions, pointez sur Ajouter, puis sélectionnez Nouvel élément.

    La boîte de dialogue Ajouter un nouvel élément s'affiche.

  2. Sélectionnez Windows Form, définissez InstructorViewer.vb ou InstructorViewer.cs comme nom du formulaire, puis cliquez sur Ajoutez.

    Un nouveau formulaire est ajouté au projet et s'ouvre dans le concepteur de formulaires. Le nom du formulaire a la valeur InstructorViewer et le texte a la valeur InstructorViewer.

  3. Faites glisser un contrôle DataGridView de la boîte à outils vers le formulaire et affectez à son champ Name la valeur instructorGridView dans la fenêtre Propriétés.

  4. Faites glisser un contrôle Button de la boîte à outils vers le formulaire. Affectez à son champ Name la valeur updateInstructor et à son champ Text la valeur Update Instructor.

  5. Faites glisser un autre contrôle Button de la boîte à outils vers le formulaire. Affectez à son champ Name la valeur viewOffices et à son champ Text la valeur View Offices.

  6. Cliquez avec le bouton droit sur le projet CourseManager dans l'Explorateur de solutions, pointez sur Ajouter, puis sélectionnez Nouvel élément.

    La boîte de dialogue Ajouter un nouvel élément s'affiche.

  7. Sélectionnez Windows Form, définissez OfficeViewer.vb ou OfficeViewer.cs comme nom du formulaire, puis cliquez sur Ajoutez.

    Un nouveau formulaire est ajouté au projet et s'ouvre dans le concepteur de formulaires. Le nom du formulaire a la valeur OfficeViewer et le texte a la valeur OfficeViewer.

  8. Faites glisser un contrôle ComboBox de la boîte à outils vers le formulaire et affectez à son champ Name la valeur instructorList.

  9. Faites glisser un contrôle TextBox de la boîte à outils vers le formulaire et affectez à son champ Name la valeur officeLocation.

  10. Faites glisser un contrôle Button de la boîte à outils vers le formulaire. Affectez à son champ Name la valeur updateOffice et à son champ Text la valeur Update Office.

  11. Dans l'Explorateur de solutions, double-cliquez sur CourseViewer.vb ou sur CourseViewer.cs.

    Le mode Création du formulaire CourseViewer apparaît.

  12. Faites glisser un contrôle Button de la boîte à outils vers le formulaire.

  13. Dans la fenêtre Propriétés, affectez à la propriété Name du Button la valeur viewInstructors et affectez à la propriété Text la valeur View Instructors.

  14. Double-cliquez sur le contrôle Button viewInstructors.

    Le fichier code-behind du formulaire CourseViewer s'ouvre.

  15. Ajoutez le code suivant au gestionnaire d'événements viewInstructors_Click :

    Dim instructorViewer As New InstructorViewer()
    instructorViewer.Visible = True
    
    InstructorViewer instructorViewer = new InstructorViewer();
    instructorViewer.Visible = true;
    
  16. Repassez en mode création du formulaire InstructorViewer.

  17. Double-cliquez sur le contrôle Button viewOffices.

    Le fichier code-behind de Form2 s'ouvre.

  18. Ajoutez le code suivant au gestionnaire d'événements viewOffices_Click :

    Dim officeViewer As New OfficeViewer()
    officeViewer.Visible = True
    
    OfficeViewer officeViewer = new OfficeViewer();
    officeViewer.Visible = true;
    

L'interface utilisateur est maintenant terminée.

Affichage et mise à jour des informations relatives aux enseignants

Dans cette procédure, vous allez ajouter du code au formulaire InstructorViewer qui vous permet d'afficher et de mettre à jour les informations relatives aux enseignants. Plus spécifiquement, le code effectue les opérations suivantes :

  • Il lie l'objet DataGridView à une requête qui retourne des informations sur les types Person qui sont des enseignants. Pour plus d'informations sur la liaison d'objets à des contrôles, voir Binding Objects to Controls (Entity Framework).

  • Il enregistre toutes les modifications (insertions, mises à jour ou suppressions) apportées au contrôle DataGridView dans la base de données.

  • Il utilise les procédures stockées que nous avons mappées précédemment pour écrire des données dans la base de données lorsque SaveChanges() est appelé dans le gestionnaire d'événements updateInstructor_Click.

Pour afficher et mettre à jour les informations relatives aux enseignants

  1. Le formulaire InstructorViewer étant ouvert dans le concepteur de formulaires, double-cliquez sur ce formulaire InstructorViewer.

    Le fichier code-behind du formulaire InstructorViewer s'ouvre.

  2. Ajoutez les instructions using (C#) ou Imports (Visual Basic) suivantes :

    Imports System.Data.Objects
    Imports System.Data.Objects.DataClasses
    
    using System.Data.Objects;
    using System.Data.Objects.DataClasses;
    
  3. Ajoutez une propriété à la classe InstructorViewer qui représente le contexte de l'objet :

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    
    // Create an ObjectContext instance based on SchoolEntity.
    private SchoolEntities schoolContext;
    
  4. Dans le gestionnaire d'événements InstructorViewer_Load, ajoutez du code pour initialiser le contexte de l'objet et affectez à la source de données du contrôle DataGridView une requête qui retourne tous les types Person qui n'ont pas un HireDate Null.

    ' Initialize the ObjectContext.
    schoolContext = New SchoolEntities()
    Dim instructorQuery As ObjectQuery(Of Person) = _
        schoolContext.People.Include("OfficeAssignment") _
        .Where("it.HireDate is not null") _
        .OrderBy("it.LastName")
    instructorGridView.DataSource = instructorQuery _
        .Execute(MergeOption.OverwriteChanges)
    instructorGridView.Columns("EnrollmentDate").Visible = False
    instructorGridView.Columns("EnrollmentDate").Visible = False
    instructorGridView.Columns("OfficeAssignment").Visible = False
    instructorGridView.Columns("StudentGrades").Visible = False
    instructorGridView.Columns("Courses").Visible = False
    
    // Initialize schoolContext.
    schoolContext = new SchoolEntities();
    
    // Define the query to retrieve instructors.
    ObjectQuery<Person> instructorQuery = schoolContext.People
        .Include("OfficeAssignment")
        .Where("it.HireDate is not null")
        .OrderBy("it.LastName");
    
    // Execute and bind the instructorList control to the query.
    instructorGridView.DataSource = instructorQuery.
        Execute(MergeOption.OverwriteChanges);
    instructorGridView.Columns["EnrollmentDate"].Visible = false;
    instructorGridView.Columns["OfficeAssignment"].Visible = false;
    instructorGridView.Columns["StudentGrades"].Visible = false;
    instructorGridView.Columns["Courses"].Visible = false;
    
  5. Repassez en mode création du formulaire InstructorViewer, puis double-cliquez sur le contrôle Button updateInstructor.

    Le gestionnaire d'événements updateInstructor_Click est ajouté au fichier code-behind.

  6. Ajoutez du code au gestionnaire d'événements updateInstructor_Click qui enregistre toutes les modifications apportées aux informations relatives aux enseignants dans le contrôle DataGridView instructorGridView.

    ' Save object changes to the database, display a 
    ' message, and refresh the form.
    schoolContext.SaveChanges()
    MessageBox.Show("Change(s) saved to the database.")
    Me.Refresh()
    
    // Save object changes to the database, display a 
    // message, and refresh the form.
    schoolContext.SaveChanges();
    MessageBox.Show("Change(s) saved to the database.");
    this.Refresh();
    

Appuyez sur Ctrl+F5 pour exécuter l'application. Les informations relatives aux enseignants peuvent maintenant être affichées et mises à jour en cliquant sur View Instructors, en apportant des modifications dans la table qui apparaît, puis en cliquant sur Update Instructor.

Affichage et mise à jour des informations relatives aux lieux de travail

Dans cette procédure, vous allez ajouter du code au formulaire OfficeViewer qui vous permet d'afficher et de mettre à jour les informations relatives aux attributions de lieux de travail. Plus spécifiquement, le code effectue les opérations suivantes :

  • Il lie l'objet ComboBox à une requête qui retourne les informations relatives aux enseignants.

  • Il affiche des adresses de lieux de travail pour l'enseignant sélectionné dans l'objet TextBox.

  • Il utilise les procédures stockées que nous avons mappées précédemment pour écrire des données dans la base de données lorsque SaveChanges() est appelé dans le gestionnaire d'événements updateOffice_Click.

Pour afficher et mettre à jour les informations relatives aux lieux de travail

  1. Le formulaire OfficeViewer étant ouvert dans le concepteur de formulaires, double-cliquez sur ce formulaire OfficeViewer.

    Le fichier code-behind du formulaire OfficeViewer s'ouvre.

  2. Ajoutez les instructions using (C#) ou Imports (Visual Basic) suivantes :

    Imports System.Data.Objects
    Imports System.Data.Objects.DataClasses
    
    using System.Data.Objects;
    using System.Data.Objects.DataClasses;
    
  3. Ajoutez une propriété à la classe OfficeViewer qui représente le contexte de l'objet :

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    
    // Create an ObjectContext instance based on SchoolEntity.
    private SchoolEntities schoolContext;
    
  4. Ajoutez la méthode suivante au formulaire :

    Private Sub ExecuteInstructorQuery()
        ' Define the query to retrieve instructors.
        Dim instructorQuery As ObjectQuery(Of Person) = _
            schoolContext.People.Include("OfficeAssignment"). _
            Where("it.HireDate is not null").OrderBy("it.LastName")
    
        'Execute and bind the instructorList control to the query.
        'Using MergeOption.OverwriteChanges overwrites local data
        'with data from the database.
        instructorList.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorList.DisplayMember = "LastName"
    End Sub
    
    private void ExecuteInstructorQuery()
    {
        // Define the query to retrieve instructors.
        ObjectQuery<Person> instructorQuery = schoolContext.People
            .Include("OfficeAssignment")
            .Where("it.HireDate is not null")
            .OrderBy("it.LastName");
    
        //Execute and bind the instructorList control to the query.
        //Using MergeOption.OverwriteChanges overwrites local data
        //with data from the database.
        instructorList.DataSource = instructorQuery
            .Execute(MergeOption.OverwriteChanges);
        instructorList.DisplayMember = "LastName";
    }
    

    Cette méthode exécute une requête que retourne des informations relatives aux enseignants et lie les résultats au contrôle ComboBox instructorList.

  5. Dans le gestionnaire d'événements OfficeViewer_Load, ajoutez du code pour initialiser le contexte de l'objet et appelez une méthode qui lie le contrôle ComboBox à une requête qui retourne tous les types Person qui n'ont pas un HireDate Null.

    schoolContext = New SchoolEntities()
    ExecuteInstructorQuery()
    
    schoolContext = new SchoolEntities();
    ExecuteInstructorQuery();
    
  6. Repassez en mode création du formulaire OfficeViewer, puis double-cliquez sur le contrôle ComboBox instructorList.

    Le gestionnaire d'événements instructorList_SelectedIndexChanged est ajouté au fichier code-behind.

  7. Ajoutez du code au gestionnaire d'événements qui affiche le lieu de travail de l'enseignant sélectionné dans le contrôle ListBox et désactivez le contrôle Button updateOffice. Ce contrôle est activé lorsqu'une modification est apportée à un lieu de travail sélectionné.

    Dim instructor As Person = CType(Me.instructorList _
     .SelectedItem(), Person)
    
    If Not instructor.OfficeAssignment Is Nothing Then
        Me.officeLocation.Text = instructor _
         .OfficeAssignment.Location.ToString()
    Else
        Me.officeLocation.Text = ""
    End If
    
    ' Disable the updateOffice button until a change
    ' has been made to the office location.
    updateOffice.Enabled = False
    
    'forceChanges.Enabled = False
    
    Person instructor = (Person)this.instructorList.
        SelectedItem;
    
    if (instructor.OfficeAssignment != null)
    {
        this.officeLocation.Text = instructor.
            OfficeAssignment.Location.ToString();
    }
    else
    {
        this.officeLocation.Text = "";
    }
    
    // Disable the updateOffice button until a change
    // has been made to the office location.
    updateOffice.Enabled = false;
    
    //forceChanges.Enabled = false;
    
  8. Repassez en mode création du formulaire OfficeViewer, puis double-cliquez sur le contrôle Button updateOffice.

    Le gestionnaire d'événements updateOffice_Click est ajouté au fichier code-behind.

  9. Ajoutez du code qui enregistre toutes les modifications apportées aux informations relatives aux lieux de travail dans le contrôle TextBox officeLocation :

    Try
        Dim currentInstructor As Person = CType(Me.instructorList _
            .SelectedItem(), Person)
        If Me.officeLocation.Text <> String.Empty Then
            If Not currentInstructor.OfficeAssignment Is Nothing Then
                currentInstructor.OfficeAssignment.Location() = _
                    Me.officeLocation.Text
            Else
                Dim temp(8) As Byte
                currentInstructor.OfficeAssignment = _
                    OfficeAssignment.CreateOfficeAssignment( _
                    currentInstructor.PersonID, _
                    Me.officeLocation.Text, temp)
            End If
        Else
            schoolContext.DeleteObject(currentInstructor. _
                                       OfficeAssignment)
        End If
        schoolContext.SaveChanges()
        MessageBox.Show("Change(s) saved to the database.")
    Catch oce As OptimisticConcurrencyException
        MessageBox.Show(oce.Message + " The conflict " & _
                "occurred on " & oce.StateEntries(0).Entity _
                .ToString() & "with key value " & _
                oce.StateEntries(0).EntityKey.EntityKeyValues(0) _
                .Value)
    
        'forceChanges.Enabled = True
    Catch ue As UpdateException
        MessageBox.Show(ue.Message & " Click OK to retrieve " _
                & "the latest data from the database.")
        ExecuteInstructorQuery()
        Me.Refresh()
    Finally
        ' Disable the updateOffice button until another
        ' change has been made to the location.
        updateOffice.Enabled = False
    End Try
    
    try
    {
        Person currentInstructor = (Person)this.instructorList.
            SelectedItem;
        if (this.officeLocation.Text != string.Empty)
        {
            if (currentInstructor.OfficeAssignment != null)
            {
                currentInstructor.OfficeAssignment.Location
                    = this.officeLocation.Text;
            }
            else
            {
                currentInstructor.OfficeAssignment
                    = OfficeAssignment.CreateOfficeAssignment(
                    currentInstructor.PersonID, this.officeLocation.Text,
                    new byte[8]);
            }
        }
        else
        {
            schoolContext.DeleteObject(currentInstructor
                .OfficeAssignment);
        }
        schoolContext.SaveChanges();
        MessageBox.Show("Change(s) saved to the database.");
    }
    catch (OptimisticConcurrencyException oce)
    {
        MessageBox.Show(oce.Message + " The conflict "
            + "occurred on " + oce.StateEntries[0].Entity
            + " with key value " + oce.StateEntries[0].
            EntityKey.EntityKeyValues[0].Value);
    
        //forceChanges.Enabled = true;
    }
    catch (UpdateException ue)
    {
        MessageBox.Show(ue.Message + " Click OK to retrieve "
            + "the latest data from the database.");
        ExecuteInstructorQuery();
        this.Refresh();
    }
    finally
    {
        // Disable the updateOffice button until another
        // change has been made to the location.
        updateOffice.Enabled = false;
    }
    
  10. Repassez en mode création du formulaire OfficeViewer, puis double-cliquez sur le contrôle TextBox officeLocation.

    Le gestionnaire d'événements officeLocation_TextChanged est ajouté au fichier code-behind.

  11. Ajoutez du code pour activer le contrôle Button updateOffice lorsqu'une modification est apportée au lieu de travail sélectionné :

    ' Enable the udateOffice button when there is a change
    ' to write to the database.
    updateOffice.Enabled = True
    
    // Enable the udateOffice button when there is a change
    // to write to the database.
    updateOffice.Enabled = true;
    

L'application est maintenant terminée. Appuyez sur Ctrl+F5 pour l'exécuter. Vous pouvez maintenant afficher et mettre à jour les informations relatives aux lieux de travail dans le formulaire OfficeViewer.

Gestion de conflits d'accès concurrentiel

Dans cette procédure, vous allez ajouter du code au formulaire Office Viewer qui force des modifications clientes sur la base de données après la survenue d'un conflit d'accès concurrentiel.

Pour gérer les conflits d'accès concurrentiel

  1. Double-cliquez sur InstructorViewer.vb ou sur InstructorViewer.cs dans l'Explorateur de solutions.

    Le formulaire s'ouvre dans le concepteur de formulaires.

  2. Double-cliquez sur le bouton View Offices.

    Le fichier code-behind du formulaire InstructorViewer s'ouvre.

  3. Ajoutez le code suivant au gestionnaire d'événements viewOffices_Click afin que deux formulaires OfficeViewer soient chargés lorsque l'utilisateur clique sur le bouton View Offices.

    Dim officeViewer2 As New OfficeViewer()
    officeViewer2.Text = "Demonstrate Conflict"
    officeViewer2.Visible = True
    
    OfficeViewer officeViewer2 = new OfficeViewer();
    officeViewer2.Text = "Demonstrate Conflict";
    officeViewer2.Visible = true;
    
  4. Double-cliquez sur OfficeViewer.vb ou sur OfficeViewer.cs dans l'Explorateur de solutions.

    Le formulaire s'ouvre dans le concepteur de formulaires.

  5. Faites glisser un contrôle Button de la boîte à outils vers le formulaire. Affectez à son champ Name la valeur forceChanges et à son champ Text la valeur Force Changes.

  6. Double-cliquez sur le bouton Force Changes.

    Le fichier code-behind du formulaire Office Viewer s'ouvre.

  7. Ajoutez le code suivant au gestionnaire d'événements forceChanges_Click afin que les modifications sur le client soient forcées sur le serveur ou que les données liées au contrôle ComboBox instructorList soit actualisé à partir de la base de données.

    Dim currentInstructor As Person = CType(Me.instructorList _
        .SelectedItem(), Person)
    Try
        currentInstructor.OfficeAssignment.Location = _
            Me.officeLocation.Text
        ' Using RefreshMode.ClientWins disables the
        ' optimistic concurrency check.
        schoolContext.Refresh(RefreshMode.ClientWins, _
                    currentInstructor.OfficeAssignment)
        schoolContext.SaveChanges()
        MessageBox.Show("Change(s) saved to the database.")
    
        'forceChanges.Enabled = False
    Catch ioe As InvalidOperationException
        MessageBox.Show(ioe.Message + " Click OK to retrieve " _
                + "the latest data from the database.")
        ExecuteInstructorQuery()
        Me.Refresh()
    End Try
    
    Person currentInstructor = (Person)this.instructorList
        .SelectedItem;
    try
    {
        currentInstructor.OfficeAssignment.Location
                    = this.officeLocation.Text;
    
        // Using RefreshMode.ClientWins disables the
        // optimistic concurrency check.
        schoolContext.Refresh(RefreshMode.ClientWins,
                currentInstructor.OfficeAssignment);
        schoolContext.SaveChanges();
        MessageBox.Show("Change(s) saved to the database.");
    
        //forceChanges.Enabled = false;
    }
    catch (InvalidOperationException ioe)
    {
        MessageBox.Show(ioe.Message + " Click OK to retrieve "
            + "the latest data from the database.");
        ExecuteInstructorQuery();
        this.Refresh();
    }
    
  8. Supprimez les marques de commentaire de la ligne de code forceChanges = False (Visual Basic) ou forceChanges = false; (C#) dans le gestionnaire d'événements instructorList_SelectedIndexChanged afin que le bouton Force Changes soit désactivé lorsqu'un nouvel enseignant est sélectionné.

  9. Supprimez les marques de commentaire de la ligne de code forceChanges = True (Visual Basic) ou forceChanges = true; (C#) dans le gestionnaire d'événements updateOffice_Click afin que le bouton Force Changes soit activé lorsqu'un conflit d'accès concurrentiel se produit.

  10. Supprimez les marques de commentaire de la ligne de code forceChanges = False (Visual Basic) ou forceChanges = false; (C#) dans le gestionnaire d'événements forceChanges_Click afin que le bouton Force Changes soit désactivé une fois que des modifications ont été forcées sur la base de données.

Pour voir l'application gérer un conflit d'accès concurrentiel, exécutez l'application (en appuyant sur Ctrl+F5), cliquez sur View Instructors, puis sur View Offices. Mettez à jour un lieu de travail dans le formulaire Office Viewer, puis essayez de mettre à jour le même lieu de travail dans l'autre formulaire Demonstrate Conflict. Un message vous notifiant le conflit d'accès concurrentiel s'affichera. Pour forcer les modifications du formulaire Demonstrate Conflict sur la base de données, cliquez sur Force Changes.

Liste de codes

Cette section contient les versions finales des fichiers code-behind pour les formulaires InstructorViewer et OfficeViewer.

Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class InstructorViewer

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities

    Private Sub viewOffices_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles viewOffices.Click
        Dim officeViewer As New OfficeViewer()
        officeViewer.Visible = True

        Dim officeViewer2 As New OfficeViewer()
        officeViewer2.Text = "Demonstrate Conflict"
        officeViewer2.Visible = True
    End Sub

    Private Sub InstructorViewer_Load(ByVal sender As System.Object, _
                    ByVal e As System.EventArgs) Handles MyBase.Load
        ' Initialize the ObjectContext.
        schoolContext = New SchoolEntities()
        Dim instructorQuery As ObjectQuery(Of Person) = _
            schoolContext.People.Include("OfficeAssignment") _
            .Where("it.HireDate is not null") _
            .OrderBy("it.LastName")
        instructorGridView.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorGridView.Columns("EnrollmentDate").Visible = False
        instructorGridView.Columns("EnrollmentDate").Visible = False
        instructorGridView.Columns("OfficeAssignment").Visible = False
        instructorGridView.Columns("StudentGrades").Visible = False
        instructorGridView.Columns("Courses").Visible = False
    End Sub

    Private Sub updateInstructor_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles updateInstructor.Click
        ' Save object changes to the database, display a 
        ' message, and refresh the form.
        schoolContext.SaveChanges()
        MessageBox.Show("Change(s) saved to the database.")
        Me.Refresh()
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace CourseManager
{
    public partial class InstructorViewer : Form
    {
        // Create an ObjectContext instance based on SchoolEntity.
        private SchoolEntities schoolContext;

        public InstructorViewer()
        {
            InitializeComponent();
        }

        private void viewOffices_Click(object sender, EventArgs e)
        {
            OfficeViewer officeViewer = new OfficeViewer();
            officeViewer.Visible = true;

            OfficeViewer officeViewer2 = new OfficeViewer();
            officeViewer2.Text = "Demonstrate Conflict";
            officeViewer2.Visible = true;
        }

        private void InstructorViewer_Load(object sender, EventArgs e)
        {
            // Initialize schoolContext.
            schoolContext = new SchoolEntities();

            // Define the query to retrieve instructors.
            ObjectQuery<Person> instructorQuery = schoolContext.People
                .Include("OfficeAssignment")
                .Where("it.HireDate is not null")
                .OrderBy("it.LastName");

            // Execute and bind the instructorList control to the query.
            instructorGridView.DataSource = instructorQuery.
                Execute(MergeOption.OverwriteChanges);
            instructorGridView.Columns["EnrollmentDate"].Visible = false;
            instructorGridView.Columns["OfficeAssignment"].Visible = false;
            instructorGridView.Columns["StudentGrades"].Visible = false;
            instructorGridView.Columns["Courses"].Visible = false;
        }

        private void updateInstructor_Click(object sender, EventArgs e)
        {
            // Save object changes to the database, display a 
            // message, and refresh the form.
            schoolContext.SaveChanges();
            MessageBox.Show("Change(s) saved to the database.");
            this.Refresh();
        }
    }
}
Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class OfficeViewer

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities

    Private Sub OfficeViewer_Load(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles MyBase.Load
        schoolContext = New SchoolEntities()
        ExecuteInstructorQuery()
    End Sub

    Private Sub instructorList_SelectedIndexChanged(ByVal sender As  _
                System.Object, ByVal e As System.EventArgs) Handles _
                instructorList.SelectedIndexChanged
        Dim instructor As Person = CType(Me.instructorList _
         .SelectedItem(), Person)

        If Not instructor.OfficeAssignment Is Nothing Then
            Me.officeLocation.Text = instructor _
             .OfficeAssignment.Location.ToString()
        Else
            Me.officeLocation.Text = ""
        End If

        ' Disable the updateOffice button until a change
        ' has been made to the office location.
        updateOffice.Enabled = False

        'forceChanges.Enabled = False
    End Sub

    Private Sub updateOffice_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles updateOffice.Click
        Try
            Dim currentInstructor As Person = CType(Me.instructorList _
                .SelectedItem(), Person)
            If Me.officeLocation.Text <> String.Empty Then
                If Not currentInstructor.OfficeAssignment Is Nothing Then
                    currentInstructor.OfficeAssignment.Location() = _
                        Me.officeLocation.Text
                Else
                    Dim temp(8) As Byte
                    currentInstructor.OfficeAssignment = _
                        OfficeAssignment.CreateOfficeAssignment( _
                        currentInstructor.PersonID, _
                        Me.officeLocation.Text, temp)
                End If
            Else
                schoolContext.DeleteObject(currentInstructor. _
                                           OfficeAssignment)
            End If
            schoolContext.SaveChanges()
            MessageBox.Show("Change(s) saved to the database.")
        Catch oce As OptimisticConcurrencyException
            MessageBox.Show(oce.Message + " The conflict " & _
                    "occurred on " & oce.StateEntries(0).Entity _
                    .ToString() & "with key value " & _
                    oce.StateEntries(0).EntityKey.EntityKeyValues(0) _
                    .Value)

            'forceChanges.Enabled = True
        Catch ue As UpdateException
            MessageBox.Show(ue.Message & " Click OK to retrieve " _
                    & "the latest data from the database.")
            ExecuteInstructorQuery()
            Me.Refresh()
        Finally
            ' Disable the updateOffice button until another
            ' change has been made to the location.
            updateOffice.Enabled = False
        End Try
    End Sub

    Private Sub officeLocation_TextChanged(ByVal sender As  _
                System.Object, ByVal e As System.EventArgs) _
                Handles officeLocation.TextChanged
        ' Enable the udateOffice button when there is a change
        ' to write to the database.
        updateOffice.Enabled = True
    End Sub

    Private Sub forceChanges_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles forceChanges.Click
        Dim currentInstructor As Person = CType(Me.instructorList _
            .SelectedItem(), Person)
        Try
            currentInstructor.OfficeAssignment.Location = _
                Me.officeLocation.Text
            ' Using RefreshMode.ClientWins disables the
            ' optimistic concurrency check.
            schoolContext.Refresh(RefreshMode.ClientWins, _
                        currentInstructor.OfficeAssignment)
            schoolContext.SaveChanges()
            MessageBox.Show("Change(s) saved to the database.")

            'forceChanges.Enabled = False
        Catch ioe As InvalidOperationException
            MessageBox.Show(ioe.Message + " Click OK to retrieve " _
                    + "the latest data from the database.")
            ExecuteInstructorQuery()
            Me.Refresh()
        End Try
    End Sub

    Private Sub ExecuteInstructorQuery()
        ' Define the query to retrieve instructors.
        Dim instructorQuery As ObjectQuery(Of Person) = _
            schoolContext.People.Include("OfficeAssignment"). _
            Where("it.HireDate is not null").OrderBy("it.LastName")

        'Execute and bind the instructorList control to the query.
        'Using MergeOption.OverwriteChanges overwrites local data
        'with data from the database.
        instructorList.DataSource = instructorQuery _
            .Execute(MergeOption.OverwriteChanges)
        instructorList.DisplayMember = "LastName"
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace CourseManager
{
    public partial class OfficeViewer : Form
    {
        // Create an ObjectContext instance based on SchoolEntity.
        private SchoolEntities schoolContext;

        public OfficeViewer()
        {
            InitializeComponent();
        }

        private void OfficeViewer_Load(object sender, EventArgs e)
        {
            schoolContext = new SchoolEntities();
            ExecuteInstructorQuery();
        }

        private void instructorList_SelectedIndexChanged(object sender,
        EventArgs e)
        {
            Person instructor = (Person)this.instructorList.
                SelectedItem;

            if (instructor.OfficeAssignment != null)
            {
                this.officeLocation.Text = instructor.
                    OfficeAssignment.Location.ToString();
            }
            else
            {
                this.officeLocation.Text = "";
            }

            // Disable the updateOffice button until a change
            // has been made to the office location.
            updateOffice.Enabled = false;

            //forceChanges.Enabled = false;
        }

        private void updateOffice_Click(object sender, EventArgs e)
        {
            try
            {
                Person currentInstructor = (Person)this.instructorList.
                    SelectedItem;
                if (this.officeLocation.Text != string.Empty)
                {
                    if (currentInstructor.OfficeAssignment != null)
                    {
                        currentInstructor.OfficeAssignment.Location
                            = this.officeLocation.Text;
                    }
                    else
                    {
                        currentInstructor.OfficeAssignment
                            = OfficeAssignment.CreateOfficeAssignment(
                            currentInstructor.PersonID, this.officeLocation.Text,
                            new byte[8]);
                    }
                }
                else
                {
                    schoolContext.DeleteObject(currentInstructor
                        .OfficeAssignment);
                }
                schoolContext.SaveChanges();
                MessageBox.Show("Change(s) saved to the database.");
            }
            catch (OptimisticConcurrencyException oce)
            {
                MessageBox.Show(oce.Message + " The conflict "
                    + "occurred on " + oce.StateEntries[0].Entity
                    + " with key value " + oce.StateEntries[0].
                    EntityKey.EntityKeyValues[0].Value);

                //forceChanges.Enabled = true;
            }
            catch (UpdateException ue)
            {
                MessageBox.Show(ue.Message + " Click OK to retrieve "
                    + "the latest data from the database.");
                ExecuteInstructorQuery();
                this.Refresh();
            }
            finally
            {
                // Disable the updateOffice button until another
                // change has been made to the location.
                updateOffice.Enabled = false;
            }
        }

        private void officeLocation_TextChanged(object sender, EventArgs e)
        {
            // Enable the udateOffice button when there is a change
            // to write to the database.
            updateOffice.Enabled = true;
        }

        private void forceChanges_Click(object sender, EventArgs e)
        {
            Person currentInstructor = (Person)this.instructorList
                .SelectedItem;
            try
            {
                currentInstructor.OfficeAssignment.Location
                            = this.officeLocation.Text;

                // Using RefreshMode.ClientWins disables the
                // optimistic concurrency check.
                schoolContext.Refresh(RefreshMode.ClientWins,
                        currentInstructor.OfficeAssignment);
                schoolContext.SaveChanges();
                MessageBox.Show("Change(s) saved to the database.");

                //forceChanges.Enabled = false;
            }
            catch (InvalidOperationException ioe)
            {
                MessageBox.Show(ioe.Message + " Click OK to retrieve "
                    + "the latest data from the database.");
                ExecuteInstructorQuery();
                this.Refresh();
            }
        }

        private void ExecuteInstructorQuery()
        {
            // Define the query to retrieve instructors.
            ObjectQuery<Person> instructorQuery = schoolContext.People
                .Include("OfficeAssignment")
                .Where("it.HireDate is not null")
                .OrderBy("it.LastName");

            //Execute and bind the instructorList control to the query.
            //Using MergeOption.OverwriteChanges overwrites local data
            //with data from the database.
            instructorList.DataSource = instructorQuery
                .Execute(MergeOption.OverwriteChanges);
            instructorList.DisplayMember = "LastName";
        }
    }
}

Étapes suivantes

Vous avez mappé avec succès les opérations d'insertion, de mise à jour et de suppression d'une entité à des procédures stockées. Pour plus d'informations sur la création d'applications qui utilisent Entity Framework, consultez Entity Framework.

Voir aussi

Autres ressources

Scénarios Entity Data Model Tools
Tâches Entity Data Model Tools