Simplified C# Database Initialization
Database initialization is the name for setting up the database and preparing the data to be presented to the user. It involves features like setting up the database, populating the data inside, and establishing relationships with other tables. The operations to be performed may vary depending on the database management system. Database initialization plays a vital role in application deployment.
Database initialization can be used in the following ways;
- Demo applications. It ensures consistency between users if the same data is used. Likewise, technical problems such as errors and what causes these errors can be diagnosed more quickly.
- Applications can employ an automatic installation procedure, initializing the database during installation or at application startup.
- If the user wants to keep it simple for small/medium-sized projects where a customer does the deployment.
Let’s create a simple project to understand better how we can implement database initialization in our projects. I am using C# .NET 7.0, Entity Framework and Postgresql for the database.
We created a simple Model called StudentModel, which consists of a StudentId, Name and a Surname. StudentId is defined as a primary key.
public class StudentModel
{
[Key]
public string StudentId { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
The database connection is set. We also specified some options on configurations and how the database is accessed. We created a relationship with the table in the database called StudentsTable. It stipulates that it should be treated as an instance of StudentModel.
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<StudentModel> StudentsTable { get; set; }
}
After defining the Model and creating the relation between databases, migration commands can be run, automatically generating the table inside the database. However, as seen in the picture, after running these commands, the table is empty.
In our Service class, we implemented a simple function to get all the students from our database.
public interface IStudentService
{
IEnumerable<StudentModel> GetAllResults();
}
public class StudentService : IStudentService
{
private readonly ApplicationDbContext dbContext;
public StudentService(ApplicationDbContext dbContext)
{
this.dbContext = dbContext;
}
public IEnumerable<StudentModel> GetAllResults()
{
return dbContext.StudentsTable.ToList();
}
}
Inside StudentController, a HttpGet action is defined to get all of the student data from the database.
public class StudentController : ControllerBase
{
private readonly IStudentService students;
public StudentController(IStudentService resultService)
{
this.students = resultService;
}
[HttpGet]
public ActionResult<IEnumerable<StudentModel>> Get()
{
var results = students.GetAllResults();
return Ok(results);
}
}
The application will call the http get function in our API if we run the application. However, it will return an empty array since it currently has no value inside of it.
We must create a Database initialization class and write the proper code to add some values to our database.
public class DatabaseInitilaizer
{
public static void Seed(IApplicationBuilder applicationBuilder)
{
using (var serviceScope = applicationBuilder.ApplicationServices.CreateScope())
{
var context = serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
if (!context.StudentsTable.Any())
{
var studentsToAdd = new List<StudentModel>
{
new StudentModel { StudentId = "1", Name = "Uğur", Surname = "Yıldırım" },
new StudentModel { StudentId = "2", Name = "Oktay", Surname = "Kızgın" },
new StudentModel { StudentId = "3", Name = "Ayşegül", Surname = "Sarı" },
new StudentModel { StudentId = "4", Name = "Altan", Surname = "Boralı" },
};
context.StudentsTable.AddRange(studentsToAdd);
context.SaveChanges();
}
}
}
}
- The Seed function takes IApplicationBuilder as a parameter. IApplicationBuilder: An object that provides the mechanisms to configure an application’s request pipeline.
- ServiceScope accesses the application’s service provider. It holds references to registered services and dependencies.
- Context retrieves instances of ApplicationDbContext from the service provider. This line is used to interact with the database.
- If condition checks the StudentTable inside the database. If that table is empty, the predefined values are added to our List<StudentModel>. With the AddRange, we can add this predefined List to our table, and it will save the changes in our database. Dbcontext provides a couple of methods to the user, such as DbContext.Add, DbContext.AddRange, DbContext.Remove, DbContext.RemoveRange, DbContext.Update, DbContext.UpdateRange etc…
The function has to be called inside Program.cs.
var app = builder.Build();
DatabaseInitilaizer.Seed(app);
If we start our application, we will see that all predefined values inside the DatabaseInitilaizer class are also stored in a database.
Thank you for taking the time to read this article. If you have any questions about the article or need help, you can reach me via Medium or Linkedin.