Introduction
In this tutorial, we will create a Blazor Server application that interacts with a DB2 for i database via NTi EF Core. We will implement a simple CRUD to manipulate the data.
We will use an example managing products, categories, and orders:
Step 1 - Project Creation and Configuration
Create a new .NET project, and choose the blazor Web App project template. In the project configuration options, select the Server Interactive Render Mode, and make sure to choose .NET 8.0.
Add the required packages:
dotnet add package Aumerial.Data.NTi
dotnet add package Aumerial.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Design
Add the connection string in appsettings.json
, and specify the default schema in which all created entities will be placed:
{
"ConnectionStrings": {
"DefaultConnection": "server=myserver;user=myuser;password=mypassword;database=mydb"
}
}
Step 2 - Defining the Entities
Create a Models folder to organize your entities, and add the following classes to model your data.
Category.cs
A category can contain multiple products.
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
Product.cs
A product belongs to a category and can be linked to multiple orders.
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
An order can contain multiple products.
public class Order
{
public int Id { get; set; }
public DateTime OrderDate { get; set; }
public DateTime? DeliveryDate { get; set; }
public decimal TotalAmount { get; set; }
}
Step 3 - DbContext Configuration
Add a class AppDbContext
that inherits from DbContext
, to manage the entities and their relationships.
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)
{
}
}
Step 4 - Configuration in Program.cs
To allow the application to use DbContext
, you must configure it in Program.cs and register it as a service via dependency injection for your Blazor components.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNti(connectionString));
- AddDbContext is recommended for most Blazor Server applications. The
DbContext
is instantiated with a Scoped lifetime, meaning it is recreated for each user request. - AddDbContextFactory is used in scenarios where the
DbContext
must be created dynamically, such as background tasks or multi-threaded processing.
Step 5 - Creating and Managing Migrations
Generate an initial migration to synchronize your entities with the database. This command will create a file in the Migrations folder containing the SQL instructions to create your tables:
dotnet ef migrations add InitialCreate
Then apply the migration to update the database and create the tables:
dotnet ef database update
To add a new table or modify an existing table, it's the same principle. Create your entities, add them in AppDbContext
, and generate a new migration to take the new table into account:
dotnet ef migrations add newEntity
Update the database to include the new table:
dotnet ef database update
If you made a mistake, you can delete the last migration before applying it:
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>
Step 6 - Adding Initial Data Set
Add a data set into the database after applying the migrations. Do this in program.cs
after registering the 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();
}
Step 7 - Generating CRUD Pages
Automatically add the CRUD pages for the entities:
Right-click on the Pages folder > Add > Razor Components with EF (CRUD).
For the Products CRUD, select Product
as the model and AppDbContext
as the context.
Step 8 - Adding a Field for Image UPLOAD (BLOB)
We will add an Image field of type byte[]
to store the image data in the database.
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; }
// New field for the image
[Column(TypeName = "BLOB(1M)"), DataType(DataType.Upload)]
public byte[] Image { get; set; }
}
We generate a migration to add the new field to the products
table, then update the database.
dotnet ef migrations add AddProductImage
dotnet ef database update
Next, you need to modify the EditProduct
and CreateProduct
components to add a field for uploading the image:
@if (Product?.Image != null && Product.Image.Length > 0)
{
Current image :
}
else
{
No image available
}
And the method to handle the 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();
}
}
Visual of the resulting CRUD on the product index page: