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’APIObjectContext
. Pour plus d’informations sur l’utilisation du contrôle EntityDataSource avec l’APIDbContext
, 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.
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.
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.
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.
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
.)
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.
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.
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.
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
.
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.
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 ».
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 .
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 SchoolEntities
et 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
.Init
DropDownList
Exécutez la page, ajoutez des informations pour un nouveau service, puis cliquez sur le lien Insérer .
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.
Cliquez sur Insérer pour afficher le message d’erreur affiché par le ValidationSummary
contrôle en bas de la page.
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.
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 laUpdate
méthode.OldValuesParameterFormatString="orig{0}"
Cela informe le contrôle que le nom du paramètre de valeurs d’origine estorigDepartment
.
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.
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.
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.