DOCUMENTATION NTi

Create a Blazor Server Application with Entity Framework Core 8

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 to manage 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 Server Interactive Render Mode, and make sure you choose .NET 8.0.

Add the necessary packages:

dotnet add package Aumerial.Data.NTi
dotnet add package Aumerial.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Design

Add the connection string to 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 - Definition of Entities

Create a Models folder to organise your entities, and add the following classes to model your data.

  • Category.cs

A category can contain several 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 several 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 may contain several 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 - Configuring DbContext

Add an AppDbContext class, which inherits from DbContext, to manage 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 enable the application to use DbContext, you need to 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, which means that it is recreated on every user request.
  • AddDbContextFactory is used for scenarios where the DbContext needs to be created dynamically, such as background tasks or multi-threaded processing.

Step 5 - Creating and managing Migrations

Generate an initial migration to synchronise your entities with the database. This command will create a file in the Migrations folder containing the SQL instructions for creating your tables:

dotnet ef migrations add InitialCreate

Then apply the migration to update the database and create the tables:

dotnet ef database update

Entité créés

The same principle applies to adding a new table or modifying an existing one. Create your entities, add them to 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 have made a mistake, you can delete the latest migration before it is applied:

dotnet ef migrations remove

If you wish to revert to an earlier version of the database, you can specify the migration name directly

dotnet ef database update <NomMigrationPrécédente>

Step 7 - Add initial data set

Add a dataset to 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 8 - Generating CRUD Pages

Add CRUD pages automatically for :

Right-click on the Pages folder > Add > Razor components with EF (CRUD).

For the Products CRUD, select Product as the template and AppDbContext as the context.

Step 9 - Adding a field for UPLOADing an image (BLOB)

We're going to 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 image field
    
    [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 it in the database.

dotnet ef migrations add AddProductImage
dotnet ef database update

Next, we 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 images available

}

And the method for managing 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 CRUD obtained from the product index page:

Utilitaire de configuration