Créer une Application Blazor Server avec Entity Framework Core 8
Introduction
Dans ce tutoriel, nous allons créer une application Blazor Server qui interagit avec une base de données DB2 for i via NTi EF Core. Nous implémenterons un CRUD simple pour manipuler les données. Nous utiliserons un exemple de gestion de produits, catégories et commandes:
Etape 1 - Création et Configuration du Projet
Créer un nouveau projet .NET, et choisissez le modèle de projet blazor Web App. Dans les options de configuration du projet, selectionnez Server Interactive Render Mode, et assurez vous de choisir .NET 8.0.
Ajoutez les packages nécessaires:
dotnet add package Aumerial.Data.NTi
dotnet add package Aumerial.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Design
Ajoutez la chaîne de connexion dans appsettings.json
, et spécifiez le schéma par défaut dans lequel toutes les entités créées seront placées:
{
"ConnectionStrings": {
"DefaultConnection": "server=myserver;user=myuser;password=mypassword;database=mydb"
}
}
Etape 2 - Définition des Entités
Créez un dossier Models pour organiser vos entités, et ajoutez les classes suivantes pour modéliser vos données.
Category.cs
Une catégorie peut contenir plusieurs produits.
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
Product.cs
Un produit appartient à une catégorie et peut être lié à plusieurs commandes.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string description { get; set; }
public decimal Price { get; set; }
public int stockQuantity { get; set; }
public decimal Weight { get; set; }
public bool IsAvailable { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
Order.cs
Une commande peut contenir plusieurs produits.
public class Order
{
public int Id { get; set; }
public DateTime OrderDate { get; set; }
public DateTime? DeliveryDate { get; set; }
public decimal TotalAmount { get; set; }
}
Etape 3 - Configuration de DbContext
ajoutez une classe AppDbContext
qui hérite de DbContext
, pour gérer les entités et leur relation.
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Order> Orders { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
Etape 4 - Configuration dans Program.cs
Pour permettre à l’application d’utiliser DbContext, vous devez le configurer dans Program.cs et l'enregistrer comme service via l'injection de dépendances pour vos composants Blazor.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNti(connectionString));
- AddDbContext est recommandé pour la plupart des applications Blazor Server. Le
DbContext
est instancié avec une durée de vie Scoped, ce qui signifie qu'il est recréé à chaque requête utilisateur. - AddDbContextFactory est utilisé pour des scénarios où le
DbContext
doit être créé dynamiquement, comme les tâches en arrière-plan ou les traitements multi-threads.
Etape 5 - Création et gestion des Migrations
Générez une migration initiale pour synchroniser vos entités avec la base de données. Cette commande va créer un fichier dans le dossier Migrations contenant les instructions SQL pour créer vos tables:
dotnet ef migrations add InitialCreate
Appliquez ensuite la migration pour mettre à jour la base de données et créer les tables :
dotnet ef database update
Pour Ajouter une nouvelle table ou modifier une table existante c'est le même principe. Créez vos entités, ajoutez la dans AppDbContext
et générez une nouvelle migrations pour prendre en compte la nouvelle table:
dotnet ef migrations add newEntity
Mettez à jour la base de données pour inclure la nouvelle table:
dotnet ef database update
Si vous avez fait une erreur, vous pouvre supprimer la dernière migration avant son application:
dotnet ef migrations remove
Si vous souhaitez revenir à une version antérieure de la base, vous pouvez spécifier directement le nom de la migration
dotnet ef database update <NomMigrationPrécédente>
Etape 7 - Ajout jeu de données initial
Ajoutez un jeu de données dans la base après application des migrations. Faite cela dans program.cs
après l'enregistrement des services:
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var categories = new List<Category>
{
new Category { Name = "Electronics" },
new Category { Name = "Books" },
new Category { Name = "Home Appliances" },
new Category { Name = "Fashion" },
new Category { Name = "Toys" }
};
context.Categories.AddRange(categories);
var products = new List<Product>
{
new Product { Name = "Smartphone", Price = 500, stockQuantity = 10, Category = categories[0], IsAvailable = true },
new Product { Name = "Laptop", Price = 1200, stockQuantity = 5, Category = categories[0], IsAvailable = true },
new Product { Name = "Washing Machine", Price = 300, stockQuantity = 8, Category = categories[2], IsAvailable = true },
new Product { Name = "T-Shirt", Price = 20, stockQuantity = 50, Category = categories[3], IsAvailable = true },
new Product { Name = "Children's Book", Price = 15, stockQuantity = 100, Category = categories[1], IsAvailable = true },
new Product { Name = "Toy Car", Price = 30, stockQuantity = 20, Category = categories[4], IsAvailable = true },
new Product { Name = "Microwave Oven", Price = 250, stockQuantity = 6, Category = categories[2], IsAvailable = true },
new Product { Name = "Jeans", Price = 40, stockQuantity = 30, Category = categories[3], IsAvailable = true }
};
context.Products.AddRange(products);
var orders = new List<Order>
{
new Order { OrderDate = DateTime.Now.AddDays(-10), DeliveryDate = DateTime.Now.AddDays(-7), TotalAmount = 750 },
new Order { OrderDate = DateTime.Now.AddDays(-5), DeliveryDate = DateTime.Now.AddDays(-3), TotalAmount = 600 },
new Order { OrderDate = DateTime.Now.AddDays(-2), DeliveryDate = null, TotalAmount = 290 }
};
context.Orders.AddRange(orders);
var orderProducts = new List<OrderProduct>
{
new OrderProduct { Order = orders[0], Product = products[0] },
new OrderProduct { Order = orders[0], Product = products[1] },
new OrderProduct { Order = orders[0], Product = products[3] },
new OrderProduct { Order = orders[1], Product = products[4] },
new OrderProduct { Order = orders[1], Product = products[5] },
new OrderProduct { Order = orders[1], Product = products[6] },
new OrderProduct { Order = orders[2], Product = products[2] },
new OrderProduct { Order = orders[2], Product = products[7] }
};
context.OrderProducts.AddRange(orderProducts);
context.SaveChanges();
}
Etape 8 - Génération des Pages CRUD
Ajoutez les pages CRUD automatiquement pour les entités :
Clic droit sur le dossier Pages > Ajouter > Composants Razor avec EF (CRUD).
Pour le CRUD Produits, sélectionnez Product
comme modèle et AppDbContext
comme contexte.
Etape 9 - Ajout d'un champ pour l'UPLOAD d'une image (BLOB)
Nous allons ajouter un champs Image de type byte[]
pour stocker les données de l'image dans la base de données.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int StockQuantity { get; set; }
public decimal Weight { get; set; }
public bool IsAvailable { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
// Nouveau champ pour l'image
[Column(TypeName = "BLOB(1M)"), DataType(DataType.Upload)]
public byte[] Image { get; set; }
}
On génère une migration pour ajouter le nouveau champs à la table products
, puis on met à jour dans la base de données.
dotnet ef migrations add AddProductImage
dotnet ef database update
Ensuite, il faut modifier les composants EditProduct
et CreateProduct
afin d'ajouter un champs pour uploader l'image:
@if (Product?.Image != null && Product.Image.Length > 0)
{
Image actuelle :
}
else
{
Aucune image disponible
}
Et la méthode pour gérer l'upload;
private async Task UploadFile(InputFileChangeEventArgs e)
{
var file = e.File;
if (file != null)
{
using var memoryStream = new MemoryStream();
await file.OpenReadStream().CopyToAsync(memoryStream);
Product.Image = memoryStream.ToArray();
}
}
Visuel du CRUD obtenu sur la page index des produits :