14
ACCEDER AUX DONNEES AVEC ADO.NET : ENTITY FRAMEWORK 6, PARTIE 1 Sommaire Introduction ............................................................................................................................................ 2 Les prérequis ........................................................................................................................................... 2 Matériel................................................................................................................................................... 2 Entity Framework 6 ................................................................................................................................. 2 Modèles EF .......................................................................................................................................... 3 Database First ......................................................................................................................................... 4 Linq to Entity ........................................................................................................................................... 7 Requêtes de sélection ......................................................................................................................... 7 Filtre ................................................................................................................................................ 8 Jointure ........................................................................................................................................... 8 Tri .................................................................................................................................................... 9 Regroupement ................................................................................................................................ 9 Agrégations ..................................................................................................................................... 9 Code First .............................................................................................................................................. 11 DbContext ......................................................................................................................................... 12 Conclusion ............................................................................................................................................. 13 Références EF6 ...................................................................................................................................... 14

ACCEDER AUX DONNEES AVEC ADO.NET - download.microsoft.comdownload.microsoft.com/documents/France/MSDN/2014/... · Code First: Vous créez des entités C#, et EF créera la base de

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

ACCEDER AUX DONNEES AVEC ADO.NET : ENTITY FRAMEWORK 6, PARTIE 1

Sommaire Introduction ............................................................................................................................................ 2

Les prérequis ........................................................................................................................................... 2

Matériel ................................................................................................................................................... 2

Entity Framework 6 ................................................................................................................................. 2

Modèles EF .......................................................................................................................................... 3

Database First ......................................................................................................................................... 4

Linq to Entity ........................................................................................................................................... 7

Requêtes de sélection ......................................................................................................................... 7

Filtre ................................................................................................................................................ 8

Jointure ........................................................................................................................................... 8

Tri .................................................................................................................................................... 9

Regroupement ................................................................................................................................ 9

Agrégations ..................................................................................................................................... 9

Code First .............................................................................................................................................. 11

DbContext ......................................................................................................................................... 12

Conclusion ............................................................................................................................................. 13

Références EF6 ...................................................................................................................................... 14

Introduction Cet article fait suite à la première partie dédiée à l’accès aux données avec ADO.NET

Nous allons aborder un nouveau concept et un Framework de haut niveau appelé Entity Framework

6, permettant d’encapsuler ce que nous avons fait dans les 2 premiers cours.

Les prérequis Ce cours s’adresse à toutes les personnes désirant comprendre les mécanismes mis en jeu lors de

l’accès aux données.

Une connaissance de C# est conseillé pour bien appréhender tous les concepts.

La connaissance des 2 premiers cours est fortement conseillée.

Matériel Pour suivre ce tutorial, vous aurez besoin de :

1. Visual Studio 2013 / Express : Le cours est basé sur Visual Studio 2013 Ultimate, mais vous

pouvez utiliser Visual Studio Express : TODO

2. SQL Server 2014 / Express / LocalDB : La base de données sera hébergée sur un server SQL.

Vous pouvez utiliser la version SQL Server qui vous convient, SQL Server 2005 à 2014 ou SQL

Server Express / LocalDB pour les versions gratuites.

3. Base de données Northwind : Cette base de données contient quelques données exemples.

Vous pouvez la télécharger ici : http://northwind.codeplex.com

4. Solutions du tutorial : L’ensemble des sources de ce cours sont disponibles ici en annexe de

ce module.

5. MySQL : Serveur MySQL local ainsi que le connecteur .NET :

http://dev.mysql.com/downloads/installer/5.6.html

6. Editeur MySQL : http://www.heidisql.com/

Entity Framework 6 Entity Framework est un mappeur objet relationnel qui permet aux développeurs d’utiliser des

données relationnelles à l’aide d’objets .NET

Le diminutif d’Entity Framework est EF. Pour plus de simplicité nous utiliserons cette abréviation

pour la suite.

EF permet de s’abstraire de tout (ou presque) le code que l’on doit généralement écrire quand on

veut accéder à une source de données.

EF se veut agnostique à la source de données, comme nous l’avons fait dans le cours N°2, le même

code sert que l’on choisisse un fournisseur d’accès SQL ou Oracle ou encore MySQL.

EF est installé par défaut dans Visual Studio et vous donne accès à un designer, comme vous pouvez

le voir dans la copie d’écran suivante :

Lorsque l’on travaille avec Entity Framework, il est important de savoir que l’on a plusieurs choix /

solutions suivant le projet sur lequel on travaille :

Modèles EF

Créer un modèle EF s’effectue suivant 2 cas : Vous possédez ou non une base de données.

Vous possédez déjà une base de données. Il vous est possible d’utiliser le mode :

Database First : Vous générez tout le modèle .NET à partir de la base de données

Code First : Vous avez déjà des entités, et vous mappez ces entités sur votre table avec EF.

Vous ne possédez pas de base de données. Il vous est possible d’utiliser le mode :

Model First : Vous créez un modèle dans le concepteur EF, qui créera la base de données au

premier lancement

Code First : Vous créez des entités C#, et EF créera la base de données au premier lancement

Dans ce cours, nous allons voir comment utiliser EF avec une base de données existante sous SQL

Server avec le modèle Database First. Dans un second temps, nous ferons évoluer le code du cours

N°2 avec le modèle Code First.

Database First

L’ajout d’un élément de type EF se fait via le menu « Ajouter nouvel élément » à votre projet,

comme dans les copies d’écrans suivants :

Une fois la génération terminée, vous avez dans votre projet un élément supplémentaire nommé

dans notre cas Northwind.edmx.

Et cet élément correspond à ce modèle :

Si vous dépliez l’arborescence de l’élément Northwind.edmx, vous allez découvrir un ensemble de

classes générées par Visual Studio pour vous, et qui correspondent aux éléments de votre schéma

Si on ouvre le fichier Customer.cs , on retrouve une classe Customer, qui ressemble fortement à la

classe Customer que nous avions créé dans les précédents cours.

C’est un des avantages de Visual Studio associé avec Entity Framework, qui va générer pour vous

tout le code nécessaire !

public partial class Customer { public Customer() { this.Orders = new HashSet<Order>(); this.CustomerDemographics = new HashSet<CustomerDemographic>(); } public string CustomerID { get; set; } public string CompanyName { get; set; } public string ContactName { get; set; } public string ContactTitle { get; set; } public string Address { get; set; } public string City { get; set; } public string Region { get; set; } public string PostalCode { get; set; } public string Country { get; set; } public string Phone { get; set; } public string Fax { get; set; } public virtual ICollection<Order> Orders { get; set; } public virtual ICollection<CustomerDemographic> CustomerDemographics { get; set; } }

Dans le fichier de configuration, vous retrouvez de même la chaine de connexion, certes un peu plus

complexe que celles que nous avons déjà utilisées dans le cours N°2 :

<add name="NorthwindEntities" connectionString="metadata=res://*/Northwind.csdl|res://*/Northwind.ssdl|res://*/Northwind.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\SQL2014;initial catalog=Northwind;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

Linq to Entity Interroger la base de données via EF6 et le code généré (on parle de modèle généré) se fait via un

langage particulier appelé Linq to Entity (Language Integrated Query)

Ce langage va nous permettre d’écrire des requêtes qui seront ensuite transformés en langage SQL

(ou Oracle ou MySQL) à partir d’un langage typé.

Les requêtes LINQ s’exécutent toujours dans le contexte de votre modèle EF6. Un peu comme l’objet

SqlCommand qui a besoin de l’ouverture d’une connexion SqlConnection.

Voici un premier exemple de l’utilisation de votre contexte EF de votre modèle Northwind :

using (NorthwindEntities context = new NorthwindEntities()) { // Votre code LINQ }

Requêtes de sélection Une première requête LINQ qui permet de récupérer tous les objets Customer de votre base

Northwind :

var query = from c in context.Customers select c;

query représente la requête à exécuter sur votre base de données.

var allCustomers = query.ToList();

allCustomers représente la List<Customer> issu de l’exécution de votre requête.

Note : L’exécution de la requête se fait lors de l’appel de la méthode ToList() et non pas lors de la

déclaration de la requête !

Voici l’exemple complet :

using (NorthwindEntities context = new NorthwindEntities()) { var query = from c in context.Customers select c; var allCustomers = query.ToList(); foreach (var customer in allCustomers) Console.WriteLine(customer.CustomerID + " " + customer.ContactName); }

A l’exécution la requête générée et exécutée sur la base de données est bien :

SELECT [Extent1].[CustomerID] AS [CustomerID], [Extent1].[CompanyName] AS [CompanyName], [Extent1].[ContactName] AS [ContactName], [Extent1].[ContactTitle] AS [ContactTitle], [Extent1].[Address] AS [Address], [Extent1].[City] AS [City], [Extent1].[Region] AS [Region], [Extent1].[PostalCode] AS [PostalCode], [Extent1].[Country] AS [Country],

[Extent1].[Phone] AS [Phone], [Extent1].[Fax] AS [Fax] FROM [dbo].[Customers] AS [Extent1]

Quelques exemples de requêtes LINQ que vous aurez surement l’occasion d’utiliser :

Filtre L’idée ici est de passer une variable comme nous aurions passé un paramètre. EF va générer une

requête paramétrée et l’exécuter sur votre base :

String filtre = "Al"; using (NorthwindEntities context = new NorthwindEntities()) { var q = from c in context.Customers where c.ContactName.StartsWith(filtre) select c; foreach (var customer in q.ToList()) Console.WriteLine(customer.CustomerID + " " + customer.ContactName); }

Et voici la requête exécutée :

exec sp_executesql N'SELECT [Extent1].[CustomerID] AS [CustomerID], [Extent1].[CompanyName] AS [CompanyName], [Extent1].[ContactName] AS [ContactName], [Extent1].[ContactTitle] AS [ContactTitle], [Extent1].[Address] AS [Address], [Extent1].[City] AS [City], [Extent1].[Region] AS [Region], [Extent1].[PostalCode] AS [PostalCode], [Extent1].[Country] AS [Country], [Extent1].[Phone] AS [Phone], [Extent1].[Fax] AS [Fax] FROM [dbo].[Customers] AS [Extent1]

WHERE [Extent1].[ContactName] LIKE @p__linq__0 ESCAPE N''~''',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'Al%'

On voit bien que la syntaxe C# StartWith() est transformée en commande SQL Like et la variable de

type string est bien remplacée par un paramètre nvarchar() nommé @p__linq__0

Jointure L’idée ici est de récupérer des éléments suivants une jointure SQL en utilisant la syntaxe from from :

var query = from e in context.Employees from r in context.Regions from t in context.Territories where t.TerritoryDescription == "Seattle" select e;

Le gros avantage ici c’est qu’il est inutile de spécifier les jointures à utiliser car elles sont déjà

connues par le modèle Northwind.

Ce n’est pas le cas dans notre modèle, mais si votre base de données ne contient pas de relations (et

donc le modèle ne les connaissant pas) vous pouvez réaliser une relation explicite comme ceci :

var query = from t in context.Territories

join r in context.Regions on t.RegionID equals r.RegionID where t.TerritoryDescription == "Seattle" select r;

Notez l’utilisation de la syntaxe « join … in … on … equals » qui permet d’établir la relation explicite

entre deux entités (donc 2 tables)

Tri L’idée ici est de trier une liste

var query = from c in context.Customers orderby c.ContactName ascending select c;

Regroupement L’idée ici est de grouper les éléments dans une nouvelle structure. Nous allons utiliser un nouveau

concept qui est l’utilisation d’un type anonyme dans la requête LINQ.

Un type anonyme permet de créer un objet dynamiquement sans forcément avoir au préalable écrit

la classe correspondante.

Il s’écrit générale de la manière suivante (dans une requête Linq)

select new { Id = 1, Prénom = "Sébastien", Nom = "Pertus" }

Dans une fonction de regroupement on a souvent une structure différente de la structure de la table

d’où l’utilisation de type anonyme.

Voici un exemple sur la table Products où l’on souhaite avoir les CategoryId pour chaque SupplierId

var query = from p in context.Products group p by new { p.CategoryID, p.SupplierID } into productGroupbyCategory select new { CategoryId = productGroupbyCategory.Key.CategoryID, SupplierID = productGroupbyCategory.Key.SupplierID }; foreach (var p in query.ToList()) Console.WriteLine(p.CategoryId + " " + p.SupplierID);

Agrégations L’idée ici est de voir les fonctions d’agrégations avec LINQ :

Moyenne (Average) :

var query = from orderDetail in context.Order_Details group orderDetail by orderDetail.ProductID into groupProd select new { ProductId = groupProd.Key, AverageQuantity = groupProd.Average(od => od.Quantity) };

foreach (var p in query.ToList()) Console.WriteLine(p.ProductId + " " + p.AverageQuantity);

Cumul (Count) :

var query = from orderDetail in context.Order_Details group orderDetail by orderDetail.ProductID into groupProd join product in context.Products on groupProd.Key equals product.ProductID orderby product.ProductName ascending select new { ProductId = groupProd.Key, ProductName = product.ProductName, Quantity = groupProd.Count() }; foreach (var p in query.ToList()) Console.WriteLine(p.ProductName + " " + p.Quantity);

Notez l’utilisation d’une jointure explicite et d’un order by pour plus de clareté.

Maximum (Max) :

var query = from orderDetail in context.Order_Details group orderDetail by orderDetail.ProductID into groupProd select new { ProductId = groupProd.Key, MaxQuantity = groupProd.Max(od => od.Quantity) };

Premier élément (First) :

using (NorthwindEntities context = new NorthwindEntities()) { var query = from c in context.Customers select c; var customer = query.First(); Console.WriteLine(customer.CustomerID + " " + customer.ContactName); }

Notez que l’opération First se fait non pas depuis la requête Linq mais lors de l’exécution avec

l’appel de la méthode First()

L’objet retourné n’est pas une List<Customer> mais un objet Customer simple.

Attention : Si il n’existe pas de ligne en base, la méthode First() va lever une exception. Si vous n’êtes

pas sûr de récupérer un enregistrement, préférez utiliser la méthode FirstOrDefault() et la

vérification de la nullité via une instruction if :

using (NorthwindEntities context = new NorthwindEntities()) { var query = from c in context.Customers where c.ContactName.Contains("Lioooooo") select c; var customer = query.FirstOrDefault(); if (customer != null) Console.WriteLine(customer.CustomerID + " " + customer.ContactName); }

Code First Le mode Code First permet de créer un contexte EF avec des entités déjà existantes. Si nous

reprenons le code du cours n° 2, nous avons déjà les entités mappées de notre base de données.

Ce sont des entités que nous avons déjà écrites en code C#.

L’idée ici c’est de se passer de toute la tuyauterie Service que nous avons écrit (CustomerServices)

avec les appels aux objets ADO.NET bas niveau comme SqlConnection, SqlCommand, etc….

Première étape : Ajouter la référence à Entity Framework, via nuget :

Vous retrouvez la référence dans votre projet :

Note : Dans le modèle Database First, cet ajout a été réalisé automatiquement par Visual Studio

pendant l’assistant de sélection de votre base de données et de vos tables.

Une fois EF6 installé, nous pouvons créer un contexte

DbContext Un objet DbContext est très similaire à l’objet généré dans le modèle Database First.

Il hérite de DbContext et fédère toutes les entités que nous souhaitons mapper à notre base de

données.

Voici la classe NorthwindContext de notre projet :

public class NorthwindContext : DbContext { public NorthwindContext() : base("name=NorthwindProd") { } public virtual DbSet<Customer> Customers { get; set; } public virtual DbSet<Category> Categories { get; set; } public virtual DbSet<Employee> Employees { get; set; } public virtual DbSet<Order> Orders { get; set; } public virtual DbSet<Product> Products { get; set; } public virtual DbSet<Region> Regions { get; set; } public virtual DbSet<Shipper> Shippers { get; set; } public virtual DbSet<Supplier> Suppliers { get; set; } public virtual DbSet<Territory> Territories { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { } }

La classe générique DbSet<T> permet de créer des collections d’objets, et rajoute des méthodes

comme l’ajout la suppression, la recherche par clé primaire etc ….

Voici une partie de la classe DbSet<T> pour information :

public class DbSet<TEntity> : DbQuery<TEntity>, IDbSet<TEntity>, IQueryable<TEntity>, IEnumerable<TEntity>, IQueryable, IEnumerable where TEntity : class { public virtual TEntity Add(TEntity entity); public virtual IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities); public virtual TEntity Attach(TEntity entity); // public virtual TEntity Create(); public virtual TEntity Find(params object[] keyValues); public virtual Task<TEntity> FindAsync(params object[] keyValues); public virtual Task<TEntity> FindAsync(CancellationToken cancellationToken, params object[] keyValues); // public virtual TEntity Remove(TEntity entity); public virtual IEnumerable<TEntity> RemoveRange(IEnumerable<TEntity> entities); public virtual DbSqlQuery<TEntity> SqlQuery(string sql, params object[] parameters); }

Conclusion Entity Framework permet notamment de simplifier l’accès aux données. Que ce soit en mode

Database First ou Code First, et l’apport de Visual Studio, vous avez l’opportunité de rapidement

vous dédouaner de toute la complexité et la tuyauterie quelque fois rébarbative de l’accès aux

données.

Dans un prochaine cours, nous allons approfondir l’utilisation d’Entity Framework pour résoudre des

problématiques liés à l’accès aux données en général.

Références EF6 Blog de l’équipe Entity Framework : http://blogs.msdn.com/b/adonet/

Site MSDN : http://msdn.microsoft.com/fr-fr/data/ef

Site Codeplex : http://entityframework.codeplex.com/