Partager via


Utilisation d’Entity Framework 4.0 et du contrôle ObjectDataSource, partie 1 : Prise en main

par Tom Dykstra

Cette série de tutoriels s’appuie sur l’application web Contoso University créée par le Prise en main avec la série de didacticiels Entity Framework 4.0. Si vous n’avez pas terminé les didacticiels précédents, comme point de départ de ce didacticiel, vous pouvez télécharger l’application que vous auriez créée. Vous pouvez également télécharger l’application créée par la série complète de tutoriels.

L’exemple d’application web Contoso University montre comment créer des applications ASP.NET Web Forms à l’aide d’Entity Framework 4.0 et de Visual Studio 2010. L’exemple d’application est un site web pour une université Contoso fictive. Il comprend des fonctionnalités telles que l’admission des étudiants, la création des cours et les affectations des formateurs.

Le tutoriel présente des exemples en C#. L’exemple téléchargeable contient du code en C# et Visual Basic.

Base de données d’abord

Il existe trois façons d’utiliser des données dans Entity Framework : Base de données d’abord, Modèle d’abord et Code First. Ce tutoriel concerne La base de données d’abord. Pour plus d’informations sur les différences entre ces flux de travail et des conseils sur la façon de choisir le meilleur pour votre scénario, consultez Flux de travail de développement Entity Framework.

Web Forms

Comme la série Prise en main, cette série de tutoriels utilise le modèle ASP.NET Web Forms et part du principe que vous savez utiliser ASP.NET Web Forms dans Visual Studio. Si ce n’est pas le cas, consultez Prise en main avec ASP.NET Web Forms 4.5. Si vous préférez utiliser l’infrastructure ASP.NET MVC, consultez Prise en main avec Entity Framework à l’aide de ASP.NET MVC.

Versions des logiciels

Présenté dans le tutoriel Fonctionne également avec
Windows 7 Windows 8
Visual Studio 2010 Visual Studio 2010 Express pour le web. Le didacticiel n’a pas été testé avec les versions ultérieures de Visual Studio. Il existe de nombreuses différences dans les sélections de menus, les boîtes de dialogue et les modèles.
.NET 4 .NET 4.5 est compatible avec .NET 4, mais le tutoriel n’a pas été testé avec .NET 4.5.
Entity Framework 4 Le didacticiel n’a pas été testé avec les versions ultérieures d’Entity Framework. À compter d’Entity Framework 5, EF utilise par défaut le DbContext API qui a été introduit avec EF 4.1. Le contrôle EntityDataSource a été conçu pour utiliser l’API ObjectContext . Pour plus d’informations sur l’utilisation du contrôle EntityDataSource avec l’API DbContext , consultez ce billet de blog.

Questions

Si vous avez des questions qui ne sont pas directement liées au didacticiel, vous pouvez les publier sur le forum ASP.NET Entity Framework, le forum Entity Framework et LINQ to Entities ou StackOverflow.com.

Le EntityDataSource contrôle vous permet de créer une application très rapidement, mais il vous oblige généralement à conserver une quantité importante de logique métier et de logique d’accès aux données dans vos pages .aspx . Si vous vous attendez à ce que votre application augmente en complexité et nécessite une maintenance continue, vous pouvez investir plus de temps de développement à l’avance afin de créer une structure d’application multiniveau ou en couches plus facile à gérer. Pour implémenter cette architecture, vous séparez la couche de présentation de la couche de logique métier (BLL) et de la couche d’accès aux données (DAL). Une façon d’implémenter cette structure consiste à utiliser le ObjectDataSource contrôle au lieu du EntityDataSource contrôle. Lorsque vous utilisez le ObjectDataSource contrôle, vous implémentez votre propre code d’accès aux données, puis vous l’appelez dans des pages .aspx à l’aide d’un contrôle qui possède un grand nombre des mêmes fonctionnalités que d’autres contrôles de source de données. Cela vous permet de combiner les avantages d’une approche multiniveau avec les avantages de l’utilisation d’un contrôle Web Forms pour l’accès aux données.

Le ObjectDataSource contrôle vous offre également plus de flexibilité d’autres façons. Étant donné que vous écrivez votre propre code d’accès aux données, il est plus facile de lire, d’insérer, de mettre à jour ou de supprimer un type d’entité spécifique, qui sont les tâches que le EntityDataSource contrôle est conçu pour effectuer. Par exemple, vous pouvez effectuer la journalisation chaque fois qu’une entité est mise à jour, archiver des données chaque fois qu’une entité est supprimée, ou case activée automatiquement et mettre à jour les données associées en fonction des besoins lors de l’insertion d’une ligne avec une valeur de clé étrangère.

Classes de logique métier et de référentiel

Un ObjectDataSource contrôle fonctionne en appelant une classe que vous créez. La classe inclut des méthodes qui récupèrent et mettent à jour des données, et vous fournissez les noms de ces méthodes au contrôle dans le ObjectDataSource balisage. Pendant le traitement du rendu ou de la publication, le ObjectDataSource appelle les méthodes que vous avez spécifiées.

Outre les opérations CRUD de base, la classe que vous créez pour utiliser avec le ObjectDataSource contrôle peut avoir besoin d’exécuter une logique métier lorsque le ObjectDataSource lit ou met à jour des données. Par exemple, lorsque vous mettez à jour un service, vous devrez peut-être vérifier qu’aucun autre service n’a le même administrateur, car une personne ne peut pas être administrateur de plusieurs services.

Dans une ObjectDataSource documentation, telle que la vue d’ensemble de la classe ObjectDataSource, le contrôle appelle une classe appelée objet métier qui inclut à la fois la logique métier et la logique d’accès aux données. Dans ce tutoriel, vous allez créer des classes distinctes pour la logique métier et pour la logique d’accès aux données. La classe qui encapsule la logique d’accès aux données est appelée référentiel. La classe de logique métier inclut à la fois des méthodes de logique métier et des méthodes d’accès aux données, mais les méthodes d’accès aux données appellent le référentiel pour effectuer des tâches d’accès aux données.

Vous allez également créer une couche d’abstraction entre votre BLL et votre DAL qui facilite les tests unitaires automatisés de la BLL. Cette couche d’abstraction est implémentée en créant une interface et en utilisant l’interface lorsque vous instanciez le dépôt dans la classe de logique métier. Cela vous permet de fournir à la classe de logique métier une référence à n’importe quel objet qui implémente l’interface du dépôt. Pour un fonctionnement normal, vous fournissez un objet de dépôt qui fonctionne avec Entity Framework. À des fins de test, vous fournissez un objet de dépôt qui fonctionne avec les données stockées d’une manière que vous pouvez facilement manipuler, comme les variables de classe définies en tant que collections.

L’illustration suivante montre la différence entre une classe de logique métier qui inclut une logique d’accès aux données sans dépôt et une classe qui utilise un dépôt.

Image05

Vous allez commencer par créer des pages web dans lesquelles le ObjectDataSource contrôle est lié directement à un dépôt, car il effectue uniquement des tâches d’accès aux données de base. Dans le tutoriel suivant, vous allez créer une classe de logique métier avec une logique de validation et lier le ObjectDataSource contrôle à cette classe au lieu de la classe du dépôt. Vous allez également créer des tests unitaires pour la logique de validation. Dans le troisième tutoriel de cette série, vous allez ajouter des fonctionnalités de tri et de filtrage à l’application.

Les pages que vous créez dans ce didacticiel fonctionnent avec le Departments jeu d’entités du modèle de données que vous avez créé dans la série de didacticiels Prise en main.

Capture d’écran montrant à quoi doit ressembler votre page Services.

Image02

Mise à jour de la base de données et du modèle de données

Vous allez commencer ce didacticiel en apportant deux modifications à la base de données, qui nécessitent toutes deux des modifications correspondantes au modèle de données que vous avez créé dans le Prise en main avec entity Framework et Web Forms tutoriels. Dans l’un de ces tutoriels, vous avez apporté des modifications manuellement au concepteur pour synchroniser le modèle de données avec la base de données après une modification de base de données. Dans ce tutoriel, vous allez utiliser l’outil Mettre à jour le modèle à partir de la base de données du concepteur pour mettre à jour automatiquement le modèle de données.

Ajout d’une relation à la base de données

Dans Visual Studio, ouvrez l’application web Contoso University que vous avez créée dans le Prise en main avec la série de didacticiels Entity Framework et Web Forms, puis ouvrez le SchoolDiagram diagramme de base de données.

Si vous examinez la Department table dans le diagramme de base de données, vous verrez qu’elle a une Administrator colonne. Cette colonne est une clé étrangère de la Person table, mais aucune relation de clé étrangère n’est définie dans la base de données. Vous devez créer la relation et mettre à jour le modèle de données afin qu’Entity Framework puisse gérer automatiquement cette relation.

Dans le diagramme de base de données, cliquez avec le bouton droit sur la Department table, puis sélectionnez Relations.

Image80

Dans la zone Relations de clé étrangère , cliquez sur Ajouter, puis sur les points de suspension pour la spécification des tables et des colonnes.

Image81

Dans la boîte de dialogue Tables et colonnes , définissez la table et le champ de clé primaire sur Person et PersonID, puis définissez la table et le champ de clés étrangères sur Department et Administrator. (Dans ce cas, le nom de la relation passe de FK_Department_Department à FK_Department_Person.)

Image82

Cliquez sur OK dans la zone Tables et colonnes , cliquez sur Fermer dans la zone Relations de clé étrangère , puis enregistrez les modifications. Si vous êtes invité à enregistrer les Person tables et Department , cliquez sur Oui.

Notes

Si vous avez supprimé Person des lignes qui correspondent à des données déjà dans la Administrator colonne, vous ne pourrez pas enregistrer cette modification. Dans ce cas, utilisez l’éditeur de table dans Server Explorer pour vous assurer que la Administrator valeur de chaque Department ligne contient l’ID d’un enregistrement qui existe réellement dans la Person table.

Après avoir enregistré la modification, vous ne pourrez pas supprimer une ligne de la Person table si cette personne est un administrateur de service. Dans une application de production, vous fournissez un message d’erreur spécifique lorsqu’une contrainte de base de données empêche une suppression, ou vous spécifiez une suppression en cascade. Pour obtenir un exemple de spécification d’une suppression en cascade, consultez Entity Framework et ASP.NET – Prise en main Partie 2.

Ajout d’une vue à la base de données

Dans la nouvelle page Departments.aspx que vous allez créer, vous souhaitez fournir une liste déroulante d’instructeurs, avec des noms au format « last, first » afin que les utilisateurs puissent sélectionner les administrateurs de service. Pour faciliter cette opération, vous allez créer une vue dans la base de données. La vue se compose uniquement des données nécessaires à la liste déroulante : le nom complet (correctement mis en forme) et la clé d’enregistrement.

Dans Server Explorer, développez School.mdf, cliquez avec le bouton droit sur le dossier Vues, puis sélectionnez Ajouter un nouvel affichage.

Image06

Cliquez sur Fermer lorsque la boîte de dialogue Ajouter une table s’affiche, puis collez l’instruction SQL suivante dans le volet SQL :

SELECT        LastName + ',' + FirstName AS FullName, PersonID
FROM          dbo.Person
WHERE        (HireDate IS NOT NULL)

Enregistrez la vue en tant que vInstructorName.

Mise à jour du modèle de données

Dans le dossier DAL , ouvrez le fichier SchoolModel.edmx , cliquez avec le bouton droit sur l’aire de conception, puis sélectionnez Mettre à jour le modèle à partir de la base de données.

Image07

Dans la boîte de dialogue Choisir vos objets de base de données , sélectionnez l’onglet Ajouter et sélectionnez la vue que vous venez de créer.

Image08

Cliquez sur Terminer.

Dans le concepteur, vous voyez que l’outil a créé une vInstructorName entité et une nouvelle association entre les Department entités et Person .

Image13

Notes

Dans les fenêtres Sortie et Liste d’erreurs , vous pouvez voir un message d’avertissement vous informant que l’outil a créé automatiquement une clé primaire pour la nouvelle vInstructorName vue. Ce comportement est normal.

Lorsque vous faites référence à la nouvelle vInstructorName entité dans le code, vous ne souhaitez pas utiliser la convention de base de données consistant à y préfixer un « v » en minuscules. Par conséquent, vous allez renommer l’entité et le jeu d’entités dans le modèle.

Ouvrez l’Explorateur de modèles. Vous voyez vInstructorName listé sous la forme d’un type d’entité et d’une vue.

Image14

Sous SchoolModel (non SchoolModel.Store), cliquez avec le bouton droit sur vInstructorName et sélectionnez Propriétés. Dans la fenêtre Propriétés , remplacez la propriété Name par « InstructorName » et remplacez la propriété Entity Set Name par « InstructorNames ».

Image15

Enregistrez et fermez le modèle de données, puis régénérez le projet.

Utilisation d’une classe repository et d’un contrôle ObjectDataSource

Créez un fichier de classe dans le dossier DAL , nommez-le SchoolRepository.cs et remplacez le code existant par le code suivant :

using System;
using System.Collections.Generic;
using System.Linq;
using ContosoUniversity.DAL;

namespace ContosoUniversity.DAL
{
    public class SchoolRepository : IDisposable
    {
        private SchoolEntities context = new SchoolEntities();

        public IEnumerable<Department> GetDepartments()
        {
            return context.Departments.Include("Person").ToList();
        }

        private bool disposedValue = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposedValue)
            {
                if (disposing)
                {
                    context.Dispose();
                }
            }
            this.disposedValue = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

    }
}

Ce code fournit une méthode unique GetDepartments qui retourne toutes les entités dans le jeu d’entités Departments . Étant donné que vous savez que vous allez accéder à la Person propriété de navigation pour chaque ligne retournée, vous spécifiez un chargement hâtif pour cette propriété à l’aide de la Include méthode . La classe implémente également l’interface IDisposable pour garantir que la connexion à la base de données est libérée lorsque l’objet est supprimé.

Notes

Une pratique courante consiste à créer une classe de dépôt pour chaque type d’entité. Dans ce tutoriel, une classe de référentiel pour plusieurs types d’entités est utilisée. Pour plus d’informations sur le modèle de dépôt, consultez les billets du blog de l’équipe Entity Framework et du blog de Julie Lerman.

La GetDepartments méthode retourne un IEnumerable objet plutôt qu’un IQueryable objet afin de s’assurer que la collection retournée est utilisable même après la suppression de l’objet de dépôt lui-même. Un IQueryable objet peut entraîner l’accès à la base de données chaque fois qu’il est accédé, mais l’objet de dépôt peut être supprimé au moment où un contrôle de trafic de données tente de restituer les données. Vous pouvez retourner un autre type de collection, tel qu’un IList objet au lieu d’un IEnumerable objet . Toutefois, le renvoi d’un IEnumerable objet garantit que vous pouvez effectuer des tâches de traitement de liste en lecture seule classiques, telles que foreach des boucles et des requêtes LINQ, mais vous ne pouvez pas ajouter ou supprimer des éléments dans la collection, ce qui peut impliquer que ces modifications seraient conservées dans la base de données.

Créez une page Departments.aspx qui utilise la page d’master Site.Master et ajoutez le balisage suivant dans le Content contrôle nommé Content2:

<h2>Departments</h2>
    <asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.DAL.SchoolRepository" 
        DataObjectTypeName="ContosoUniversity.DAL.Department" 
        SelectMethod="GetDepartments" >
    </asp:ObjectDataSource>
    <asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
        DataSourceID="DepartmentsObjectDataSource"  >
        <Columns>
            <asp:CommandField ShowEditButton="True" ShowDeleteButton="True"
                ItemStyle-VerticalAlign="Top">
            </asp:CommandField>
            <asp:DynamicField DataField="Name" HeaderText="Name" SortExpression="Name" ItemStyle-VerticalAlign="Top" />
            <asp:DynamicField DataField="Budget" HeaderText="Budget" SortExpression="Budget" ItemStyle-VerticalAlign="Top" />
            <asp:DynamicField DataField="StartDate" HeaderText="Start Date" ItemStyle-VerticalAlign="Top" />
            <asp:TemplateField HeaderText="Administrator" SortExpression="Person.LastName" ItemStyle-VerticalAlign="Top" >
                <ItemTemplate>
                    <asp:Label ID="AdministratorLastNameLabel" runat="server" Text='<%# Eval("Person.LastName") %>'></asp:Label>,
                    <asp:Label ID="AdministratorFirstNameLabel" runat="server" Text='<%# Eval("Person.FirstMidName") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

Ce balisage crée un ObjectDataSource contrôle qui utilise la classe de dépôt que vous venez de créer et un GridView contrôle pour afficher les données. Le GridView contrôle spécifie les commandes Modifier et Supprimer , mais vous n’avez pas encore ajouté de code pour les prendre en charge.

Plusieurs colonnes utilisent DynamicField des contrôles pour vous permettre de tirer parti des fonctionnalités de mise en forme et de validation automatiques des données. Pour que celles-ci fonctionnent, vous devez appeler la EnableDynamicData méthode dans le gestionnaire d’événements Page_Init . (DynamicControl les contrôles ne sont pas utilisés dans le Administrator champ, car ils ne fonctionnent pas avec les propriétés de navigation.)

Les Vertical-Align="Top" attributs deviendront importants ultérieurement lorsque vous ajouterez une colonne qui a un contrôle imbriqué GridView à la grille.

Ouvrez le fichier Departments.aspx.cs et ajoutez l’instruction suivante using :

using ContosoUniversity.DAL;

Ajoutez ensuite le gestionnaire suivant pour l’événement de la Init page :

protected void Page_Init(object sender, EventArgs e)
{
    DepartmentsGridView.EnableDynamicData(typeof(Department));
}

Dans le dossier DAL , créez un fichier de classe nommé Department.cs et remplacez le code existant par le code suivant :

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace ContosoUniversity.DAL
{
    [MetadataType(typeof(DepartmentMetaData))]
    public partial class Department
    {
    }

    public class DepartmentMetaData
    {
        [DataType(DataType.Currency)]
        [Range(0, 1000000, ErrorMessage = "Budget must be less than $1,000,000.00")]
        public Decimal Budget { get; set; }

        [DisplayFormat(DataFormatString="{0:d}",ApplyFormatInEditMode=true)]
        public DateTime StartDate { get; set; }

    }
}

Ce code ajoute des métadonnées au modèle de données. Elle spécifie que la Budget propriété de l’entité représente réellement la Department devise bien que son type de données soit Decimal, et elle spécifie que la valeur doit être comprise entre 0 et 1 000 000 ,00 $. Il spécifie également que la StartDate propriété doit être mise en forme en tant que date au format mm/jj/aaaa.

Exécutez la page Departments.aspx .

Capture d’écran montrant la page Départements lorsqu’elle a été exécutée.

Notez que même si vous n’avez pas spécifié de chaîne de format dans le balisage de page Departments.aspx pour les colonnes Budget ou Date de début , la devise et la mise en forme de date par défaut leur ont été appliquées par les DynamicField contrôles, à l’aide des métadonnées que vous avez fournies dans le fichier Department.cs .

Ajout de fonctionnalités d’insertion et de suppression

Ouvrez SchoolRepository.cs, ajoutez le code suivant afin de créer une Insert méthode et une Delete méthode. Le code inclut également une méthode nommée GenerateDepartmentID qui calcule la prochaine valeur de clé d’enregistrement disponible à utiliser par la Insert méthode . Cela est obligatoire, car la base de données n’est pas configurée pour calculer automatiquement cette valeur pour la Department table.

public void InsertDepartment(Department department)
{
    try
    {
        department.DepartmentID = GenerateDepartmentID();
        context.Departments.AddObject(department);
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        //Include catch blocks for specific exceptions first,
        //and handle or log the error as appropriate in each.
        //Include a generic catch block like this one last.
        throw ex;
    }
}

public void DeleteDepartment(Department department)
{
    try
    {
        context.Departments.Attach(department);
        context.Departments.DeleteObject(department);
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        //Include catch blocks for specific exceptions first,
        //and handle or log the error as appropriate in each.
        //Include a generic catch block like this one last.
        throw ex;
    }
}

private Int32 GenerateDepartmentID()
{
    Int32 maxDepartmentID = 0;
    var department = (from d in GetDepartments()
                      orderby d.DepartmentID descending
                      select d).FirstOrDefault();
    if (department != null)
    {
        maxDepartmentID = department.DepartmentID + 1;
    }
    return maxDepartmentID;
}

Méthode Attach

La DeleteDepartment méthode appelle la Attach méthode afin de rétablir le lien qui est conservé dans le gestionnaire d’état d’objet du contexte d’objet entre l’entité en mémoire et la ligne de base de données qu’elle représente. Cela doit se produire avant que la méthode appelle la SaveChanges méthode .

Le terme contexte d’objet fait référence à la classe Entity Framework qui dérive de la ObjectContext classe que vous utilisez pour accéder à vos jeux d’entités et entités. Dans le code de ce projet, la classe est nommée SchoolEntitieset une instance de celle-ci est toujours nommée context. Le gestionnaire d’état d’objet du contexte d’objet est une classe qui dérive de la ObjectStateManager classe . Le contact d’objet utilise le gestionnaire d’état d’objet pour stocker des objets d’entité et pour vérifier si chacun d’eux est synchronisé avec la ou les lignes de la table correspondantes dans la base de données.

Lorsque vous lisez une entité, le contexte de l’objet la stocke dans le gestionnaire d’état de l’objet et effectue le suivi de la synchronisation de cette représentation de l’objet avec la base de données. Par exemple, si vous modifiez une valeur de propriété, un indicateur est défini pour indiquer que la propriété que vous avez modifiée n’est plus synchronisée avec la base de données. Ensuite, lorsque vous appelez la SaveChanges méthode, le contexte de l’objet sait quoi faire dans la base de données, car le gestionnaire d’état d’objet sait exactement ce qui est différent entre l’état actuel de l’entité et l’état de la base de données.

Toutefois, ce processus ne fonctionne généralement pas dans une application web, car le contexte d’objet instance qui lit une entité, ainsi que tout ce qui se trouve dans son gestionnaire d’état d’objet, est supprimé après le rendu d’une page. Le contexte d’objet instance qui doit appliquer des modifications est un nouveau contexte instancié pour le traitement de la publication. Dans le cas de la DeleteDepartment méthode, le ObjectDataSource contrôle recrée la version d’origine de l’entité à partir de valeurs dans l’état d’affichage, mais cette entité recréé Department n’existe pas dans le gestionnaire d’état d’objet. Si vous appelez la DeleteObject méthode sur cette entité recréé, l’appel échoue, car le contexte de l’objet ne sait pas si l’entité est synchronisée avec la base de données. Toutefois, l’appel de la Attach méthode rétablit le même suivi entre l’entité recréée et les valeurs de la base de données qui a été effectuée automatiquement à l’origine lorsque l’entité a été lue dans un instance précédent du contexte de l’objet.

Parfois, vous ne souhaitez pas que le contexte de l’objet effectue le suivi des entités dans le gestionnaire d’état d’objet, et vous pouvez définir des indicateurs pour l’empêcher de le faire. Vous en trouverez des exemples dans les didacticiels ultérieurs de cette série.

La méthode SaveChanges

Cette classe de dépôt simple illustre les principes de base pour effectuer des opérations CRUD. Dans cet exemple, la SaveChanges méthode est appelée immédiatement après chaque mise à jour. Dans une application de production, vous pouvez appeler la SaveChanges méthode à partir d’une méthode distincte pour vous donner plus de contrôle sur la mise à jour de la base de données. (À la fin du tutoriel suivant, vous trouverez un lien vers un livre blanc qui traite du modèle d’unité de travail, qui est une approche de la coordination des mises à jour associées.) Notez également que dans l’exemple, la méthode n’inclut pas de DeleteDepartment code pour la gestion des conflits d’accès concurrentiel ; le code à cet effet sera ajouté dans un didacticiel ultérieur de cette série.

Récupération des noms d’instructeurs à sélectionner lors de l’insertion

Les utilisateurs doivent être en mesure de sélectionner un administrateur dans une liste d’instructeurs dans une liste déroulante lors de la création de nouveaux services. Par conséquent, ajoutez le code suivant à SchoolRepository.cs pour créer une méthode permettant de récupérer la liste des instructeurs à l’aide de la vue que vous avez créée précédemment :

public IEnumerable<InstructorName> GetInstructorNames()
{
    return context.InstructorNames.OrderBy("it.FullName").ToList();
}

Création d’une page pour l’insertion de services

Créez une page DepartmentsAdd.aspx qui utilise la page Site.Master et ajoutez le balisage suivant dans le Content contrôle nommé Content2:

<h2>Departments</h2>
    <asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.DAL.SchoolRepository" DataObjectTypeName="ContosoUniversity.DAL.Department"
        InsertMethod="InsertDepartment" >
    </asp:ObjectDataSource>
    <asp:DetailsView ID="DepartmentsDetailsView" runat="server" 
        DataSourceID="DepartmentsObjectDataSource" AutoGenerateRows="False"
        DefaultMode="Insert" OnItemInserting="DepartmentsDetailsView_ItemInserting">
        <Fields>
            <asp:DynamicField DataField="Name" HeaderText="Name" />
            <asp:DynamicField DataField="Budget" HeaderText="Budget" />
            <asp:DynamicField DataField="StartDate" HeaderText="Start Date" />
            <asp:TemplateField HeaderText="Administrator">
                <InsertItemTemplate>
                    <asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server" 
                        TypeName="ContosoUniversity.DAL.SchoolRepository" 
                        DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
                        SelectMethod="GetInstructorNames" >
                    </asp:ObjectDataSource>
                    <asp:DropDownList ID="InstructorsDropDownList" runat="server" 
                        DataSourceID="InstructorsObjectDataSource"
                        DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init">
                    </asp:DropDownList>
                </InsertItemTemplate>
            </asp:TemplateField>
            <asp:CommandField ShowInsertButton="True" />
        </Fields>
    </asp:DetailsView>
   <asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server" 
        ShowSummary="true" DisplayMode="BulletList"  />

Ce balisage crée deux ObjectDataSource contrôles, l’un pour insérer de nouvelles Department entités et l’autre pour récupérer les noms des instructeurs pour le DropDownList contrôle utilisé pour sélectionner les administrateurs de service. Le balisage crée un DetailsView contrôle pour l’entrée de nouveaux services et spécifie un gestionnaire pour l’événement du ItemInserting contrôle afin que vous puissiez définir la valeur de clé Administrator étrangère. À la fin se trouve un ValidationSummary contrôle pour afficher les messages d’erreur.

Ouvrez DepartmentsAdd.aspx.cs et ajoutez l’instruction suivante using :

using ContosoUniversity.DAL;

Ajoutez la variable de classe et les méthodes suivantes :

private DropDownList administratorsDropDownList;

protected void Page_Init(object sender, EventArgs e)
{
    DepartmentsDetailsView.EnableDynamicData(typeof(Department));
}

protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
    administratorsDropDownList = sender as DropDownList;
}

protected void DepartmentsDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
    e.Values["Administrator"] = administratorsDropDownList.SelectedValue;
}

La Page_Init méthode active la fonctionnalité Dynamic Data. Le gestionnaire de l’événement du contrôle enregistre une référence au contrôle, et le gestionnaire de l’événement DetailsView du Inserting contrôle utilise cette référence pour obtenir la valeur de l’instructeur PersonID sélectionné et mettre à jour la Administrator propriété de clé étrangère de l’entitéDepartment.InitDropDownList

Exécutez la page, ajoutez des informations pour un nouveau service, puis cliquez sur le lien Insérer .

Image04

Entrez les valeurs d’un autre nouveau service. Entrez un nombre supérieur à 1 000 000,00 dans le champ Budget et tabulation jusqu’au champ suivant. Un astérisque apparaît dans le champ, et si vous maintenez le pointeur de la souris dessus, vous pouvez voir le message d’erreur que vous avez entré dans les métadonnées de ce champ.

Image03

Cliquez sur Insérer pour afficher le message d’erreur affiché par le ValidationSummary contrôle en bas de la page.

Image12

Ensuite, fermez le navigateur et ouvrez la page Departments.aspx . Ajoutez une fonctionnalité de suppression à la page Departments.aspx en ajoutant un DeleteMethod attribut au ObjectDataSource contrôle et un DataKeyNames attribut au GridView contrôle. Les balises d’ouverture de ces contrôles ressemblent désormais à l’exemple suivant :

<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.DAL.SchoolRepository" 
        DataObjectTypeName="ContosoUniversity.DAL.Department"
        SelectMethod="GetDepartments" 
        DeleteMethod="DeleteDepartment" >

    <asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
        DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID" >

Exécutez la page.

Capture d’écran montrant la page Services après son exécution.

Supprimez le service que vous avez ajouté lorsque vous avez exécuté la page DepartmentsAdd.aspx .

Ajout d’une fonctionnalité de mise à jour

Ouvrez SchoolRepository.cs et ajoutez la méthode suivante Update :

public void UpdateDepartment(Department department, Department origDepartment)
{
    try
    {
        context.Departments.Attach(origDepartment);
        context.ApplyCurrentValues("Departments", department);
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        //Include catch blocks for specific exceptions first,
        //and handle or log the error as appropriate in each.
        //Include a generic catch block like this one last.
        throw ex;
    }
}

Lorsque vous cliquez sur Mettre à jour dans la page Departments.aspx , le ObjectDataSource contrôle crée deux Department entités à passer à la UpdateDepartment méthode. L’une contient les valeurs d’origine qui ont été stockées dans l’état d’affichage, et l’autre contient les nouvelles valeurs qui ont été entrées dans le GridView contrôle. Le code dans la UpdateDepartment méthode passe l’entité Department qui a les valeurs d’origine à la Attach méthode afin d’établir le suivi entre l’entité et ce qui se trouve dans la base de données. Ensuite, le code passe l’entité Department qui a les nouvelles valeurs à la ApplyCurrentValues méthode. Le contexte de l’objet compare les anciennes et les nouvelles valeurs. Si une nouvelle valeur est différente d’une ancienne valeur, le contexte de l’objet modifie la valeur de la propriété. La SaveChanges méthode met ensuite à jour uniquement les colonnes modifiées dans la base de données. (Toutefois, si la fonction de mise à jour de cette entité était mappée à une procédure stockée, la ligne entière serait mise à jour quelles que soient les colonnes modifiées.)

Ouvrez le fichier Departments.aspx et ajoutez les attributs suivants au DepartmentsObjectDataSource contrôle :

  • UpdateMethod="UpdateDepartment"
  • ConflictDetection="CompareAllValues"
    Cela entraîne le stockage des anciennes valeurs dans l’état d’affichage afin qu’elles puissent être comparées aux nouvelles valeurs de la Update méthode.
  • OldValuesParameterFormatString="orig{0}"
    Cela informe le contrôle que le nom du paramètre de valeurs d’origine est origDepartment .

Le balisage de la balise d’ouverture du ObjectDataSource contrôle ressemble maintenant à l’exemple suivant :

<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.DAL.SchoolRepository" 
        DataObjectTypeName="ContosoUniversity.DAL.Department" 
        SelectMethod="GetDepartments" DeleteMethod="DeleteDepartment" 
        UpdateMethod="UpdateDepartment"
        ConflictDetection="CompareAllValues" 
        OldValuesParameterFormatString="orig{0}" >

Ajoutez un OnRowUpdating="DepartmentsGridView_RowUpdating" attribut au GridView contrôle. Vous l’utiliserez pour définir la valeur de la Administrator propriété en fonction de la ligne sélectionnée par l’utilisateur dans une liste déroulante. La GridView balise d’ouverture ressemble maintenant à l’exemple suivant :

<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
        DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID"
        OnRowUpdating="DepartmentsGridView_RowUpdating">

Ajoutez un EditItemTemplate contrôle pour la Administrator colonne au GridView contrôle, immédiatement après le ItemTemplate contrôle de cette colonne :

<EditItemTemplate>
                    <asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server" DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
                        SelectMethod="GetInstructorNames" TypeName="ContosoUniversity.DAL.SchoolRepository">
                    </asp:ObjectDataSource>
                    <asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsObjectDataSource"
                        SelectedValue='<%# Eval("Administrator")  %>'
                        DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init" >
                    </asp:DropDownList>
                </EditItemTemplate>

Ce EditItemTemplate contrôle est similaire au InsertItemTemplate contrôle de la page DepartmentsAdd.aspx . La différence est que la valeur initiale du contrôle est définie à l’aide de l’attribut SelectedValue .

Avant le GridView contrôle, ajoutez un ValidationSummary contrôle comme vous l’avez fait dans la page DepartmentsAdd.aspx .

<asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server" 
        ShowSummary="true" DisplayMode="BulletList"  />

Ouvrez Departments.aspx.cs et immédiatement après la déclaration de classe partielle, ajoutez le code suivant pour créer un champ privé pour référencer le DropDownList contrôle :

private DropDownList administratorsDropDownList;

Ajoutez ensuite des gestionnaires pour l’événement DropDownList du Init contrôle et l’événement GridView du RowUpdating contrôle :

protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
    administratorsDropDownList = sender as DropDownList;
}

protected void DepartmentsGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    e.NewValues["Administrator"] = administratorsDropDownList.SelectedValue;
}

Le gestionnaire de l’événement Init enregistre une référence au DropDownList contrôle dans le champ de classe. Le gestionnaire de l’événement RowUpdating utilise la référence pour obtenir la valeur entrée par l’utilisateur et l’appliquer à la Administrator propriété de l’entité Department .

Utilisez la page DepartmentsAdd.aspx pour ajouter un nouveau service, puis exécutez la page Departments.aspx et cliquez sur Modifier sur la ligne que vous avez ajoutée.

Notes

Vous ne pourrez pas modifier les lignes que vous n’avez pas ajoutées (c’est-à-dire qui se trouvaient déjà dans la base de données), en raison de données non valides dans la base de données ; les administrateurs des lignes qui ont été créées avec la base de données sont des étudiants. Si vous essayez de modifier l’un d’eux, vous obtiendrez une page d’erreur qui signale une erreur comme 'InstructorsDropDownList' has a SelectedValue which is invalid because it does not exist in the list of items.

Image10

Si vous entrez un montant budgétaire non valide, puis cliquez sur Mettre à jour, vous voyez le même astérisque et le même message d’erreur que vous avez vu dans la page Departments.aspx .

Modifiez une valeur de champ ou sélectionnez un autre administrateur, puis cliquez sur Mettre à jour. La modification s’affiche.

Capture d’écran montrant la page Services.

Cela termine l’introduction à l’utilisation du contrôle pour les ObjectDataSource opérations CRUD de base (créer, lire, mettre à jour, supprimer) avec Entity Framework. Vous avez créé une application simple à plusieurs niveaux, mais la couche logique métier est toujours étroitement couplée à la couche d’accès aux données, ce qui complique les tests unitaires automatisés. Dans le tutoriel suivant, vous allez voir comment implémenter le modèle de dépôt pour faciliter les tests unitaires.