Installation globale de l’outil EF Core CLI :
> dotnet tool install --global dotnet-ef
Installation des packages nécessaires dans le répertoire du projet :
> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
DbContext
qui représente une session d’échanges (lecture/écriture de données) avec une BD. Elle spécifie les classes du modèle à synchroniser avec la BD.> dotnet ef migrations add {MigrationName}
Crée une nouvelle migration dans le répertoire Migrations/ du projet. Elle contient les mises à jour à réaliser au niveau du schéma relationnel pour le synchroniser avec le modèle objet.
> dotnet ef database update
Synchronise la base de données configurée par le contexte BD avec la migration la plus récente.
SaveChanges()
implante dans la BD tous les changements ayant eu lieu depuis l’ouverture de la session.using (var context = new {App}Context())
{
// ... (Opérations on model classes)
// Synchronize all changes with database
context.SaveChanges();
}
dotnet new console -o EFBlog
cd EFBlog
dotnet new gitignore
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.9" />
</ItemGroup>
</Project>
Chaque classe est codée dans son propre fichier .cs
, dans le sous-répertoire Models/
du projet.
public class Blog
{
public int Id { get; set; }
public string Url { get; set; } = null!;
public List<Post> Posts { get; } = new List<Post>();
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; } = null!;
public string Content { get; set; } = null!;
public int BlogId { get; set; }
public Blog Blog { get; set; } = null!;
}
null
(donc qu’elle pourra être déréférencée sans risque).= null!
permet d’initialiser les propriétés C# gérées par EF Core dans le contexte null-aware de .NET 6+.Classe créée dans le sous-répertoire Data/
du projet.
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; } = null!;
public DbSet<Post> Posts { get; set; } = null!;
public string DbPath { get; private set; }
public BloggingContext()
{
// Path to SQLite database file
DbPath = "EFBlog.db";
}
// The following configures EF to create a SQLite database file locally
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
// Use SQLite as database
options.UseSqlite($"Data Source={DbPath}");
// Optional: log SQL queries to console
options.LogTo(Console.WriteLine, new[] { DbLoggerCategory.Database.Command.Name }, LogLevel.Information);
}
}
(dotnet-ef
doit avoir été installé globalement)
dotnet ef migrations add InitialCreate
dotnet ef database update
migrationBuilder.CreateTable(
name: "Blogs",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Url = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Blogs", x => x.Id);
});
Capture d’écran de DB Browser pour SQLite :
La colonne BlogId
est une clé étrangère vers la colonne Id
de la table Blogs
.
using (var context = new BloggingContext())
{
Console.WriteLine("--- Inserting a new blog ---");
context.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
context.SaveChanges();
Console.WriteLine("--- Retrieve blog with lowest id ---");
var blog = context.Blogs
.OrderBy(b => b.Id)
.First();
Console.WriteLine("--- Updating the blog and adding a post ---");
blog.Url = "https://devblogs.microsoft.com/dotnet";
blog.Posts.Add(
new Post { Title = "Hello World", Content = "I wrote an app using EF Core!" });
context.SaveChanges();
Console.WriteLine("--- Deleting the blog ---");
context.Remove(blog);
context.SaveChanges();
}
Language Integrated Query (LINQ) est le langage standard pour le requêtage en C#, quelle que soit la source de données (SGBDR, XML, service web, etc).
using (var context = new BloggingContext())
{
// Retrieve a list of blogs with a rating greater than 3,
// ordered by URL
var blogs = context.Blogs
.Where(b => b.Rating > 3)
.OrderBy(b => b.Url)
.ToList();
}
using (var context = new BloggingContext())
{
// Get all blogs
var blogs = context.Blogs.ToList();
// Get the blog with id 1
var blog = context.Blogs
.Single(b => b.Id == 1);
// Get all blogs containing "dotnet" in their URL
var blogs = context.Blogs
.Where(b => b.Url.Contains("dotnet"))
.ToList();
}
Plus de détails :
Pour plus de souplesse, il est possible de manipuler des requêtes LINQ en tant que variables.
using (var context = new BloggingContext())
{
// Get all blogs containing "dotnet" in their URL
var query = from b in context.Blogs
select b;
query = query.Where(b => b.Url.Contains("dotnet"));
var blogs = query.ToList();
}
Effectuée via des annotations dans les classes du modèle.
public class Blog
{
public int Id { get; set; }
[StringLength(200, MinimumLength = 7), Required]
public string Url { get; set; }
[Display(Name = "Average Rating")]
[Column(TypeName = "decimal(5, 2)")]
[DisplayFormat(NullDisplayText = "No rating")]
public decimal? Rating { get; set; }
// ...
null
. La colonne BD associée accepte les valeurs nulles.[Required]
permet de rendre obligatoire une propriété ayant un type référence (exemple : string
).int?
, bool?
) rend la propriété optionnelle.Id
ou {NomDeLaClasse}Id
est considérée comme clé primaire.public class Blog
{
public int Id { get; set; }
// ...
public List<Post> Posts { get; set; } = new List<Post>();
}
public class Post
{
public int Id { get; set; }
// ...
public int BlogId { get; set; } // FK
public Blog Blog { get; set; } // Navigation
}
public class Blog
{
public int Id { get; set; }
// ...
public BlogImage BlogImage { get; set; }
}
public class BlogImage
{
public int Id { get; set; }
public byte[] Image { get; set; }
public string Caption { get; set; }
public int BlogId { get; set; } // FK
public Blog Blog { get; set; }
}
Entraîne la création d’une table de jointure contenant deux clés étrangères dans la base de données.
public class Post
{
public int Id { get; set; }
// ...
public ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public string Id { get; set; }
public ICollection<Post> Posts { get; set; }
}
.Include()
et .ThenInclude()
permettent de spécifier les données associées à inclure dans les résultats d’une requête.using (var context = new BloggingContext())
{
// Load posts for each blog
// Uncomment the .ThenInclude line to load post author
var blogs = context.Blogs
.Include(blog => blog.Posts)
// .ThenInclude(post => post.Author)
.ToList();
}
Discriminator
qui détermine le type concret de l’objet stocké en BD.internal class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<RssBlog> RssBlogs { get; set; }
// ...
}
public class Blog
{
public int BlogId { get; set; }
// ...
}
public class RssBlog : Blog
{
public string RssUrl { get; set; }
// ...
}
dotnet ef migrations add RssBlog
dotnet ef database update