Entity Framework Core est l'ORM de référence dans l'écosystème .NET. Il permet de manipuler une base de données directement depuis des objets C#, sans écrire de SQL manuellement : les requêtes, les migrations et le mapping sont gérés automatiquement.
Grâce à l'extension Entity Framework Core pour IBM i avec NTi, cette approche s'applique désormais nativement à DB2 for i. Compatible avec .NET 8, .NET 9 et .NET 10, les développeurs .NET peuvent travailler avec une base IBM i exactement comme avec n'importe quelle autre base de données supportée par EF Core, avec le même outillage, les mêmes conventions et les mêmes commandes. Le projet présenté dans ce tutoriel utilise .NET 8.
Étape 1 - Créer et configurer le projet
Créez le projet depuis la ligne de commande :
dotnet new blazorserver -n myApp --framework net8.0
cd myApp
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 en spécifiant le schéma par défaut dans lequel toutes les entités créées seront placées :
{
"ConnectionStrings": {
"DefaultConnection": "server=Server;user=User;password=Pwd;database=Db"
}
}Étape 2 - Définir les entités
Créez un dossier Models et ajoutez les classes suivantes :
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; }
public ICollection<Order> Orders { get; set; } = new List<Order>();
}
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; }
public ICollection<Product> Products { get; set; }
}Étape 3 - Configurer le DbContext
Ajoutez une classe AppDbContext héritant de DbContext pour gérer les entités et leurs relations:
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)
{
}
}Étape 4 - Configurer Program.cs
Configurez le DbContext dans Program.cs et enregistrez-le 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));
💡
AddDbContextest recommandé pour la plupart des applications Blazor Server. LeDbContextest instancié avec une durée de vie Scoped, recréé à chaque requête utilisateur. UtilisezAddDbContextFactorypour les tâches en arrière-plan ou les traitements multi-threads.
Étape 5 - Créer et gérer les migrations
Générez une migration initiale pour créer les tables dans 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 :
dotnet ef database update

Pour ajouter ou modifier une table, créez ou modifiez l'entité concernée, ajoutez-la dans AppDbContext si nécessaire, puis générez une nouvelle migration :
dotnet ef migrations add MyNewMigration
dotnet ef database update
Pour supprimer la dernière migration avant son application :
dotnet ef migrations remove
Pour revenir à une version antérieure de la base :
dotnet ef database update MigrationName
Remplacez
MigrationNamepar le nom de la migration vers laquelle vous souhaitez revenir
Étape 6 - Ajouter un jeu de données initial
Ajoutez un jeu de données 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,
Products = new List<Product> { products[0], products[1], products[3] }
},
new Order
{
OrderDate = DateTime.Now.AddDays(-5),
DeliveryDate = DateTime.Now.AddDays(-3),
TotalAmount = 600,
Products = new List<Product> { products[4], products[5], products[6] }
},
new Order
{
OrderDate = DateTime.Now.AddDays(-2),
DeliveryDate = null,
TotalAmount = 290,
Products = new List<Product> { products[2], products[7] }
}
};
context.Orders.AddRange(orders);
context.SaveChanges();
}Étape 7 - Générer les pages CRUD
Visual Studio peut générer automatiquement les composants Razor CRUD pour chacune de vos entités en quelques clics.
- Clic droit sur le dossier Pages de votre projet Blazor Server
- Sélectionnez Ajouter > Nouvel élément généré automatiquement > Composants Razor avec Entity Framework (CRUD)
- Configurez les options :
- Classe de Modèle : sélectionnez l'entité souhaitée (ex.
Product) - Classe de DbContext : sélectionnez
AppDbContext
- Classe de Modèle : sélectionnez l'entité souhaitée (ex.
Visual Studio génère automatiquement un ensemble de composants Razor CRUD dans un dossier dédié (ex. ProductPages) :
Index.razor- liste des enregistrementsCreate.razor- formulaire d'ajoutEdit.razor- formulaire de modificationDetails.razor- affichage du détail d'un enregistrementDelete.razor- confirmation et suppression
Répétez l'opération pour chaque entité : Category, Order.
Étape 8 - Ajouter un champ image (BLOB)
Ajoutez un champ Image de type byte[] à l'entité Product :
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; }
[Column(TypeName = "BLOB(1M)"), DataType(DataType.Upload)]
public byte[] Image { get; set; }
}
Générez et appliquez la migration :
dotnet ef migrations add AddProductImage
dotnet ef database update
Modifiez ensuite les composants EditProduct et CreateProduct pour ajouter le champ d'upload :
<div class="mb-3">
<label for="image" class="form-label">Image:</label>
<InputFile id="image" OnChange="UploadFile" class="form-control" />
@if (Product?.Image != null && Product.Image.Length > 0)
{
<p>Image actuelle :</p>
<img src="data:image/jpeg;base64,@Convert.ToBase64String(Product.Image)"
style="max-width: 200px; max-height: 200px;" />
}
else
{
<p>Aucune image disponible</p>
}
</div>
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();
}
}

Quentin Destrade