Loupe

EF CORE - Comment bien démarrer ?

Entity Framework (EF) est un framework d'accès aux données développé par Microsoft. Ce framework fête cette année, ses 10 ans ! Depuis ces 10 années d'existence, il en est à sa version 6 pour la version standard, et en version 2.0 pour la version .Net CORE. Dans cet article, nous allons nous concentrer sur la version .Net CORE de celui-ci. Pour ceux ayant déjà utilisé la version 6, ils ne seront pas dépaysés, les bases restent les mêmes !

Avant de poursuivre, sur comment utiliser EF Core, il est préférable de garder en tête que les deux versions (standard et .Net CORE) ne sont pas équivalentes en termes de fonctionnalités. Il faut donc bien étudier votre besoin pour ainsi choisir la version qui vous convient le mieux. Pour cela Microsoft propose un dossier qui permet de faire ce choix en ayant toutes les informations nécessaires. Les différences notables selon moi, et qui peuvent faire pencher la balance pour ou contre EF CORE sont :

Vous pouvez retrouver la liste complètes des différences entres les 2 versions ici. Si vous souhaitez également en savoir plus sur l'utilisation d'EF CORE in-memory a des fins des tests, je vous invite a lire mon article sur le sujet.

Maintenant que nous savons pourquoi utiliser EF CORE, voyons voir comment mettre en place EF CORE en partant de zéro. Nous allons prendre comme exemple la réalisation d'une base de données permettant de gérer des entreprises et des employés.

Etape 1 : Créer les classes des entités

Une entité est la définition C# d'une table en SQL, il suffit de créer simplement une classe C# et de définir ses propriétés. Nous allons donc créer une classe "Employee".

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Notre entité prête, nous allons maintenant passer à la création du contexte EF. Le contexte EF permet de définir quelles entités doit manipuler EF et définir les paramètres des ces entités (relations, propriétés ...). Il est intéressant de savoir qu'il n'est pas obligatoire de définir toutes les tables de sa base de données dans l'application si celle-ci ne seront pas manipulées par l'application.

Etape 2 : Créer le contexte EF et mapper les entités

 Avant de commencer à utiliser EF CORE dans une application, il faut ajouter le package NuGet suivant :

Install-Package Microsoft.EntityFrameworkCore

Une fois fait, il suffit de créer une classe qui hérite de la classe Microsoft.EntityFrameworkCore.DbContext. C'est la classe de base permettant de manipuler des entités avec EF. Elle expose de nombreuses méthodes (la plupart sont également disponibles en version asynchrone), que vous serez amené à utiliser, en voici quelques-unes :

  • les méthodes Add, AddRange pour ajouter de nouveaux enregistrements 
  • la méthode SaveChanges pour commit les modifications sur votre contexte
public class ConfigContext : DbContext
{
    public ConfigContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<Employee> Employees { get; set; }
}

Notre contexte n'est pour le moment pas très détaillé, nous avons juste ajouté une propriété "Employees". Ce sont des propriétés de type Microsoft.EntityFrameworkCore.DbSet. Pour faire simple, un DbSet représente les méthodes permettant de manipuler les données de l'entité qu'il représente (en utilisant des requêtes LINQ). Il est donc nécessaire de "mapper" en tant que DbSet, toutes les entités que l'on souhaite manipuler dans notre application. 

Etape 3 : Paramétrer les entités

Maintenant que les entités sont mappées au contexte, il faut décrire au contexte comment chacune des entités est définie en SQL (nom de la table SQL, clé primaire, relations, ...). Pour ce faire il existe deux méthodes, soit directement dans chacune des classes des entités à travers des attributs (data annotation), soit dans le contexte EF en utilisant "fluent api". Personnellement, préfère la seconde méthode pour paramétrer les entités et ce pour deux raisons. La première car j'estime que les classes des entités doivent rester le plus simple possible et qu'ajouter des attributs, alourdi grandement la lecture. La seconde car le paramétrage des entités doit à mon sens, être centralisé à un endroit pour plus de lisibilité (dans le contexte).

Le paramétrage en "fluent api" se fait dans la méthode OnModelCreating du contexte, cette méthode est exposée dans la classe de base Microsoft.EntityFrameworkCore.DbContext. Il suffit donc de l'overrider pour pouvoir y définir le paramétrage.

Le nom de la table et le schéma

Il est utile de définir un nom de table si celui-ci est différent du nom de l'entité C#. Pour le schéma SQL, il est utile de le définir si il est différent du "dbo" classique.

Via annotation

[Table("Employees", Schema = "MonSchema")]
public class Employee
{
}

Via Fluent Api

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var employeeBuilder = modelBuilder.Entity<Employee>();
    employeeBuilder.ToTable("Employees", "MonSchema");

    base.OnModelCreating(modelBuilder);
}

Il est également possible en Fluent Api, de définir un schéma global (pratique si toutes vos tables utilisent le même schéma). En utilisant la méthode HasDefaultSchema comme ceci : 

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasDefaultSchema("MonSchema");

    base.OnModelCreating(modelBuilder);
}

Le nom des colonnes

Il est utilise de définir le nom de la colonne si celui-ci est différent du nom de la propriété dans la classe C#.

Via annotation

public class Employee
{
    [Column("EmployeeId")]
    public int Id { get; set; }
}

Via Fluent Api

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var employeeBuilder = modelBuilder.Entity<Employee>();
    employeeBuilder.Property(e => e.Id).HasColumnName("EmployeeId");

    base.OnModelCreating(modelBuilder);
}

La clé primaire

La clé primaire doit être définie pour toutes les entités qui seront manipulées par EF.

Via annotation

public class Employee
{
    [Key]
    public int Id { get; set; }
}

Via Fluent Api

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var employeeBuilder = modelBuilder.Entity<Employee>();
    employeeBuilder.HasKey(c => c.Id);

    base.OnModelCreating(modelBuilder);
}

Dans le cas d'une clé primaire composée, il est nécessaire de spécifier les propriétés de la clé et l'ordre :

Via annotation

public class Employee
{
    [Key]
    [Column(Order = 1)]
    public int Id { get; set; }

    [Key]
    [Column(Order = 2)]
    public string LastName { get; set; }
}

Via Fluent Api

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var employeeBuilder = modelBuilder.Entity<Employee>();
    employeeBuilder.HasKey(c => new { c.Id, c.LastName });

    base.OnModelCreating(modelBuilder);
}

Les valeurs générées par la base de données

Certaines valeurs des propriétés de l'entité sont gérées par la base de données, c'est elle qui renseigne leur valeur, il faut donc le préciser à EF, il en existe deux :

  • générées à l'ajout (clé primaire par exemple),
  • générées à l'ajout et à la modification (colonne calculée par exemple)

Pour la génération à l'ajout, il faut définir comme cela :

Via annotation

public class Employee
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
}

Via Fluent Api

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var employeeBuilder = modelBuilder.Entity<Employee>();
    employeeBuilder.Property(e => e.Id).ValueGeneratedOnAdd();

    base.OnModelCreating(modelBuilder);
}

Pour la génération à l'ajout et à la modification, il faut définir comme cela :

Via annotation

public class Employee
{
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public int Id { get; set; }
}

Via Fluent Api

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var employeeBuilder = modelBuilder.Entity<Employee>();
    employeeBuilder.Property(e => e.Id).ValueGeneratedOnAddOrUpdate();

    base.OnModelCreating(modelBuilder);
}

Etape 4 : Utiliser le contexte

Une fois le paramétrage effectué, nous allons pouvoir utiliser le contexte et ainsi effectuer les opérations avec la base de données ! En fonction de votre fournisseur de base de données, vous n'allez pas utiliser les mêmes méthodes, mais le principe reste le même. Pour ceux qui sont attentifs, vous avez remarqué que le constructeur du contexte demande un objet de type Microsoft.EntityFrameworkCore.DbContextOptions, c'est dans ces options qu'est défini le fournisseur de base de données. EF CORE supporte de nombreux fournisseurs de base de données la liste est disponnible ici.

Pour créer l'object DbContextOptions, il faut utiliser un Microsoft.EntityFrameworkCore.DbContextOptionsBuilder comme ceci (j'utilise le fournisseur in-memory dans mon exemple) :

var options = new DbContextOptionsBuilder<ConfigContext>()
                        .UseInMemoryDatabase(Guid.NewGuid().ToString())
                        .Options;

Une fois l'objet créé, il ne reste plus qu'a le donner au constructeur du contexte :

var context = new ConfigContext(options);

 

Et voilà c'est terminé, le contexte est prêt pour manipuler les données de votre base de données !

Photo de profil

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus