In addition, we have added a static OnModelCreating method. Inside that method, we tell Entity Framework to link PostCategory with Post, using the PostId. As well as that, we also tell Entity Framework to link PostCategory with Category, using the CategoryId.
The DbContext
Now that we have created our entities, we can set up our DbContext for Entity Framework. The "OnModelCreating" method is overridden to add our entities to our DbContext.
We have used some reflection to find all types that inherit "IBase" and invoked the static "OnModelCreating" method on each type, if it exists. In addition, we have also invoked the static "OnModelCreating" on the "Base" class for each type, using the type we are on as it's generic method. This ensures that we set the Id as the primary key for each type. This follows a similar approach to the one I took in my article "Using Reflection to Create a Dynamic OnModelCreating in Entity Framework".
In addition, we also override the "OnConfiguring" method so we can get the connection string for our database from our appsettings.json file. You will need to ensure that the Nuget package "Microsoft.EntityFrameworkCore.SqlServer" has been added to the project.
// RoundTheCodeBlazorDbContext.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
namespace RoundTheCode.Blazor.Data
{
public class RoundTheCodeBlazorDbContext : DbContext
{
protected IConfiguration _configuration;
public RoundTheCodeBlazorDbContext()
{
_configuration = new ConfigurationBuilder().AddJsonFile(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\appsettings.json").Build();
}
public RoundTheCodeBlazorDbContext([NotNull] IConfiguration configuration)
{
_configuration = configuration;
}
protected override void OnModelCreating(ModelBuilder builder)
{
// Loads all types from an assembly which have an interface of IBase and is a public class
var types = Assembly.GetExecutingAssembly().GetTypes().Where(s => s.GetInterfaces().Any(_interface => _interface.Equals(typeof(IBase)) && s.IsClass && !s.IsAbstract && s.IsPublic));
foreach (var type in types)
{
// On Model Creating
var onModelCreatingMethod = type.GetMethods().FirstOrDefault(x => x.Name == "OnModelCreating" && x.IsStatic);
if (onModelCreatingMethod != null)
{
onModelCreatingMethod.Invoke(type, new object[] { builder });
}
// On Base Model Creating
if (type.BaseType == null || type.BaseType != typeof(Base))
{
continue;
}
var baseOnModelCreatingMethod = type.BaseType.GetMethods().FirstOrDefault(x => x.Name == "OnModelCreating" && x.IsStatic);
if (baseOnModelCreatingMethod == null)
{
continue;
}
var baseOnModelCreatingGenericMethod = baseOnModelCreatingMethod.MakeGenericMethod(new Type[] { type });
if (baseOnModelCreatingGenericMethod == null)
{
continue;
}
baseOnModelCreatingGenericMethod.Invoke(typeof(Base), new object[] { builder });
}
}
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
// Sets the database connection from appsettings.json
builder.UseSqlServer(_configuration["ConnectionStrings:RoundTheCodeBlazorDbContext"]);
}
public async override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
foreach (var entry in ChangeTracker.Entries())
{
if (entry.Entity is IBase)
{
if (entry.State == EntityState.Added)
{
entry.Property("Created").CurrentValue = DateTimeOffset.Now;
}
else if (entry.State == EntityState.Modified)
{
entry.Property("LastUpdated").CurrentValue = DateTimeOffset.Now;
}
}
}
return await base.SaveChangesAsync(cancellationToken);
}
}
}
Adding Entity Framework to our Application
Now that we have set up Entity Framework, we need to add it to our Blazor application. This is relatively simple to do. You just need to add the following line into the ConfigureServices method in the Startup class.
// Startup.cs
services.AddDbContext<RoundTheCodeBlazorDbContext>(options => { }, ServiceLifetime.Transient);
The reason why we use transient is documented in my article "Using Entity Framework in a Blazor Server Application".
Next, we need to create our SQL Server database. We open up SQL Server Management Studio and create a new database called "RoundTheCodeBlazor".
// appsettings.json
"ConnectionStrings": {
"RoundTheCodeBlazorDbContext": "Server=localhost;Database=RoundTheCodeBlazor;Trusted_Connection=True;MultipleActiveResultSets=true;Integrated Security = true;"
}
Migration of Entities to Database
At present, we have an empty database with no tables. We need to fix that. For that, we use Entity Framework migrations. Before you do that, you need to ensure that the Nuget package "Microsoft.EntityFrameworkCore.Tools" is installed. This contains the migration script that we are going to use.
Then it's a simple case of going to Tools -> NuGet Package Manager -> Package Manager Console in Visual Studio and typing the following:
Lastly, we need to add our connection string into our appsettings.json file. This will look something like this.
Add-Migration Initial
This will set up our scripts to migrate the Category, Post and PostCategory entities to our database. At this point, it will not actually perform the migration. We need to run another script in the Package Manager Console to do this:
Update-Database
As a result of this, you should see your entities appearing in your database. Assuming no errors were reported.
See Entity Framework Running in the Application
Time to see a successful implementation of Entity Framework in Blazor. The video below shows the steps to get EF working in Blazor. In addition, it demonstrates a working example of calling a query from Entity Framework and displaying that data in the Blazor application.