---
sidebar_label: '2.1. Naming conventions (Entity Framework Code First)'
sidebar_position: 1
description: "explique quelles sont les conventions d'écriture utilisées pour la transformation d'une entité en table"
---

# Entity Framework CodeFirst Conventions
*02/01/2020 &sdot; Marc Chevaldonné*  

---

Le lien entre une base de données et vos classes à l'aide de **Entity Framework Core** se fait via une classe dérivant de ```DbContext```.
Cette classe doit contenir des ```DbSet<T>```. Chaque ```DbSet<T>``` correspond à une table et ```T``` correspond à une de vos classes qu'on appelle *entité*.
Le lien entre les tables et les entités est géré plus ou moins automatiquement par le *framework*.   
**EF Core** permet de lire/écrire les instances d'entité de la base de données ; permet de créer des tables pour les entités via les migrations (pour les bases de données relationnelles) ;
les types exposés dans les propriétés d'une entité deviennent automatiquement des entités (mais pas forcément des tables)

**Entity Framework Core** propose 3 solutions différentes pour relier des entités à des tables de la base de données :
* **conventions d'écriture** : c'est la solution la plus simple, qui analyse le code de votre classe pour en déduire de quelle manière la relier à la table.
* **data annotations** : elle se base sur des décorateurs (appelés *data annotations*) que vous placez autour de vos propriétés pour indiquer de quelle manière les relier aux colonnes de votre table. Les *data annotations* écrasent les conventions d'écriture.
* **Fluent API** : directement dans le code de votre ```DbContext``` (plus précisément, dans la méthode ```OnModelCreating```), vous précisez comment se fait le *mapping* entre votre entité et votre table. La *Fluent API* écrase les conventions d'écriture et les *data annotations*.

En d'autres termes, si vous n'écrivez rien, **EF Core** utilise les conventions d'écriture ; si vous n'utilisez que des *data annotations*, elles sont prioritaires sur les convetions d'écriture ; si vous utilisez la *Fluent API*, elle est prioritaire sur les deux autres méthodes.
Mais on peut faire un mix des différentes méthodes.

Cet exemple montre de quelle manière les **conventions d'écriture** sont utilisées pour transformer une entité en table.
Il montre notamment :
* comment le nom de la table est choisi
* s'il est possible d'ignorer une propriété de l'entité
* comment le nom et le type d'une colonne de la table sont choisis
* comment un identifiant unique est choisi et généré.

Cet exemple est répété d'une manière très similaire en utilisant les autres méthodes de *mapping* entre entité et table :
* [**2.2. data annotations**](../Entity-Framework/Model/EF_CF_dataAnnotations)
* [**2.3. Fluent API**](../Entity-Framework/Model/EF_CF_FluentAPI)

---

## Comment est construit cet exemple ?
* Le projet est de type .NET Core
* Il contient deux classes :
  * ```Nounours```
  * ```NounoursDBEntities```

### La classe ```NounoursDBEntities```
* Cette classe dérive de ```DbContext```. Elle contient des ```DbSet<T>``` où ```T``` est une entité. Elle contient autant de ```DbSet<T>``` que de tables.
```csharp title='NounoursDBEntities.cs'
class NounoursDBEntities : DbContext
{
    public DbSet<Nounours> NounoursSet { get; set; }
}
```
ici, on indique donc qu'il y aura une table de ```Nounours```.
* **EF Core** utilisera cette classe pour faire la création de la base de données et de ses tables. Pour cela, elle utilise la chaîne de connexion donnée dans la méthode ```OnConfiguring```.
```csharp title='NounoursDBEntities.cs'
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ex_042_001_EF_CF_conventions.Nounours.mdf;Trusted_Connection=True;");
}
```
=> cf **ex_041_001_ConnectionStrings** pour en savoir plus sur les chaîne de connexion  
* Dans cet exemple, la table de ```Nounours``` est créée en utilisant les conventions d'écriture de la classe ```Nounours```.

### La classe ```Nounours```
* ```Nounours``` est une entité, on parle aussi de classe POCO, i.e. Plain Old CLR Object.
```csharp title='Nounours.cs'
public class Nounours
{
    public int ID
    {
        get; set;
    }

    public string Nom
    {
        get;
        set;
    }

    public DateTime DateDeNaissance
    {
        get;
        set;
    }

    public int NbPoils
    {
        get;
        set;
    }
}
```
* Elle contient 3 propriétés en lecture/écriture : ```Nom```, ```DateDeNaissance``` et ```NbPoils```. Nous parlerons de la 4ème (```ID```) dans un moment.
* **Entity Framework Core** va utiliser la classe POCO ```Nounours``` pour créer une table dans la base de données, lorsque le ```DbSet``` va être créé.
* L'utilisation des conventions d'écriture d'Entity Framework font que la table qui va être créée aura :
    * un nom correspondant au nom de la classe POCO : ici "Nounours"
    * une colonne pour chaque propriété publique : ici, "Nom", "DateDeNaissance" et "NbPoils"
* De plus, en rajoutant une propriété de type int et avec le nom "ID", Entity Framework ajoute directement une colonne "ID" et l'utilise comme clé primaire.

**En résumé** :
* le nom de la table est choisi automatiquement (c'est le nom de l'entité)
* toutes les propriétés ayant un getter et un setter publiques sont des colonnes de la table
* le nom des colonnes est choisi automatiquement (il s'agit du nom des propriétés)
* il n'est pas possible d'ignorer une propriété
* le type d'une colonne est imposé par un *mapping* automatique entre les types .NET et ceux de la base de données. Par exemple :
  * un ```DateTime``` est transformé en ```datetime2(7)```
  * un ```string``` est transformé en ```nvarchar(max)```
  * si c'est une clé, elle est transformée en ```nvarchar(450)```
  * ...
* si la classe possède une propriété de type ```int``` s'appelant ```ID```, elle est automatiquement utilisée comme clé primaire générée par lz base de données lors de l'insertion

### La classe ```Program```
Cette classe est le point d'entrée du programme :
* Elle crée des instances de ```Nounours```
```csharp title='Program.cs'
Nounours chewie = new Nounours { Nom = "Chewbacca", DateDeNaissance = new DateTime(1977, 5, 27), NbPoils = 1234567 };
Nounours yoda = new Nounours { Nom = "Yoda", DateDeNaissance = new DateTime(1980, 5, 21), NbPoils = 3 };
Nounours ewok = new Nounours { Nom = "Ewok", DateDeNaissance = new DateTime(1983, 5, 25), NbPoils = 3456789 };
```
* Elle démarre une connexion à la base de données
```csharp title='Program.cs'
using (NounoursDBEntities db = new NounoursDBEntities())
{
//...
}
```
* Elle vérifie si la table est vide, et si ce n'est pas le cas, elle la vide.  
Notez l'accès à la table de ```Nounours``` via ```db.NounoursSet```.  
Notez également que tant que ```SaveChanges``` n'est pas appelée, les suppressions ne sont pas effectives dans la base, seulement en local dans le programme.  
_Cette partie de l'exemple ne s'exécutera que si la base existe déjà, par exemple lors d'une deuxième exécution._
```csharp title='Program.cs'
if (db.NounoursSet.Count() > 0)
{
    WriteLine("La base n'est pas vide !");
    foreach (var n in db.NounoursSet)
    {
        WriteLine($"\t{n}");
    }
    WriteLine("début du nettoyage...");

    foreach (var n in db.NounoursSet.ToArray())
    {
        WriteLine($"Suppression de {n}");
        db.NounoursSet.Remove(n);
    }

    WriteLine("Base avant sauvegarde des changements :");
    foreach (var n in db.NounoursSet)
    {
        WriteLine($"\t{n}");
    }
    db.SaveChanges();
    WriteLine("Base après sauvegarde des changements :");
    foreach (var n in db.NounoursSet)
    {
        WriteLine($"\t{n}");
    }
}
```
* Elle ajoute ensuite les ```Nounours```et sauvegarde les changements pour que ceux-ci soit effectivement ajoutés à la base.
```csharp
db.NounoursSet.AddRange(new Nounours[] { chewie, yoda, ewok });

db.SaveChanges();
WriteLine("Base après ajout des 3 nounours et sauvegarde des changements :");
foreach (var n in db.NounoursSet)
{
    WriteLine($"\t{n}");
}
``` 

## Comment exécuter cet exemple ?
Pour tester cette application, n'oubliez pas les commandes comme présentées dans l'exemple ex_041_001 : pour générer l'exemple, il vous faut d'abord préparer les migrations et les tables.
  * Ouvrez la *Console du Gestionnaire de package*, pour cela, dirigez-vous dans le menu *Outils*, puis *Gestionnaire de package NuGet*, puis *Console du Gestionnaire de package*.
  * Dans la console que vous venez d'ouvrir, déplacez-vous dans le dossier du projet .NET Core, ici :
```
cd .\p08_BDD_EntityFramework\ex_042_001_EF_CF_conventions
``` 

:::note
  si vous n'avez pas installé correctement EntityFrameworkCore, il vous faudra peut-être utiliser également :

* ```dotnet tool install --global dotnet-ef``` si vous utilisez la dernière version de .NET Core (3.1 aujourd'hui),  

* ```dotnet tool install --global dotnet-ef --version 3.0.0``` si vous vous utiliser spécifiquement .NET Core 3.0.
:::

  * Migration : 
```
dotnet ef migrations add migration_ex_042_001
```
  * Création de la table :
```
dotnet ef database update
```
  * Génération et exécution
Vous pouvez maintenant générer et exécuter l'exemple **ex_042_001_EF_CF_conventions**.

  * Le résultat de l'exécution doit ressembler à :
    ```
    Base après ajout des 3 nounours et sauvegarde des changements :
          1: Chewbacca (27/05/1977, 1234567 poils)
          2: Yoda (21/05/1980, 3 poils)
          3: Ewok (25/05/1983, 3456789 poils)
    ```

:::note
les identifiants peuvent varier en fonction du nombre d'exécutions
:::

  * Comment vérifier le contenu des bases de données SQL Server ?
Vous pouvez vérifier le contenu de votre base en utilisant l'*Explorateur d'objets SQL Server*.
* Pour cela, allez dans le menu *Affichage* puis *Explorateur d'objets SQL Server*.  
![Sql Server](../Fundamentals/ConnectionStringsFiles/sqlserver_01.png)  

* Déployez dans l'*Explorateur d'objets SQL Server* :
  *  *SQL Server*, 
  *  puis *(localdb)\MSSQLLocalDB ...*, 
  *  puis *Bases de données*
  *  puis celle portant le nom de votre migration, dans mon cas : *ex_042_001_EF_CF_conventions.NounoursSet.mdf*
  *  puis *Tables*   
  *  Faites un clic droit sur la table *dbo.Nounours* puis choisissez *Afficher les données*  
![Sql Server](../Fundamentals/ConnectionStringsFiles/sqlserver_02.png)  

  *  Vous devriez maintenant pouvoir voir les données suivantes dans le tableau :  
 
  |ID   |Nom|DateDeNaissance|NbPoils
  |---|---|---|---
  |1|Chewbacca|27/05/1977 00:00:00|1234567
  |2|Yoda|21/05/1980 00:00:00|3
  |3|Ewok|25/05/1983 00:00:00|3456789  

:::note
les identifiants peuvent varier en fonction du nombre d'exécution de l'exemple depuis la création de la base de données.
:::