CoursMVAAccederAuxDonnees 4EntityFramework6, Part1

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 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
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/

Vous aimerez peut-être aussi