Setting up DbContext

To interact with data as objects/entity classes, EF uses the Microsoft.EntityFrameworkCore.DbContext class also called DbContext or simply Context. This class is in charge of all the entity objects during execution, including populating them with data from the database, keeping track of changes, and persisting them to the database during CRUD operations.

We can easily create our very own DbContext class for our project, which we will call ApplicationDbContext, by performing the following tasks:

Right-click on the /OpenGameList/Data folder and add a new ApplicationDbContext.cs class. Fill it up with the following code:

using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 
using Microsoft.EntityFrameworkCore; 
using Microsoft.EntityFrameworkCore.Metadata; 
using OpenGameListWebApp.Data.Items; 
using OpenGameListWebApp.Data.Users; 
using OpenGameListWebApp.Data.Comments; 
 
namespace OpenGameListWebApp.Data 
{ 
    public class ApplicationDbContext : DbContext 
    { 
        #region Constructor 
        public ApplicationDbContext(DbContextOptions options) : base(options) 
        { 
        } 
        #endregion Constructor 
 
        #region Methods 
        protected override void OnModelCreating(ModelBuilder modelBuilder) 
        { 
            base.OnModelCreating(modelBuilder); 
 
modelBuilder.Entity<ApplicationUser>().ToTable("Users"); 
            modelBuilder.Entity<ApplicationUser>().HasMany(u => u.Items).WithOne(i => i.Author); 
            modelBuilder.Entity<ApplicationUser>().HasMany(u => u.Comments).WithOne(c => c.Author).HasPrincipalKey(u => u.Id); 
 
            modelBuilder.Entity<Item>().ToTable("Items"); 
            modelBuilder.Entity<Item>().Property(i => i.Id).ValueGeneratedOnAdd(); 
            modelBuilder.Entity<Item>().HasOne(i => i.Author).WithMany(u => u.Items); 
            modelBuilder.Entity<Item>().HasMany(i => i.Comments).WithOne(c => c.Item); 
 
            modelBuilder.Entity<Comment>().ToTable("Comments"); 
            modelBuilder.Entity<Comment>().HasOne(c => c.Author).WithMany(u => u.Comments).HasForeignKey(c => c.UserId).OnDelete(DeleteBehavior.Restrict); 
            modelBuilder.Entity<Comment>().HasOne(c => c.Item).WithMany(i => i.Comments); 
            modelBuilder.Entity<Comment>().HasOne(c => c.Parent).WithMany(c => c.Children); 
            modelBuilder.Entity<Comment>().HasMany(c => c.Children).WithOne(c => c.Parent); 
        } 
        #endregion Methods 
 
        #region Properties 
        public DbSet<Item> Items { get; set; } 
        public DbSet<Comment> Comments { get; set; } 
        public DbSet<ApplicationUser> Users { get; set; } 
        #endregion Properties 
    } 
} 

There are a number of things worth noting here:

  • In the second constructor method's implementation, we set the DbInitializer, which is the class that will handle the database initialization strategy. If you're used to EF6 you know why we need to do this, otherwise don't worry as we'll get there in the following paragraph.
  • We overrode the OnModelCreating method to manually define our data model relationships for our ApplicationUser, Item, and Comment entity classes. Notice that we manually configured the table names for each entity using the modelBuilder.Entity<TEntityType>().ToTable method. We did that with the sole purpose of showing how easy it is to customize the code-first generated database.
  • Finally, we added a DbSet property for each of our entities, so we can easily access them later on.

Database initialization strategies

Creating the database for the first time isn't the only thing we need to worry about, for example, how can we keep tracks of the changes that will definitely occur to our data model?

In EF's previous versions, we could choose between one of the database management patterns (known as database initializers or DbInitializers) offered by the code-first approach, that is picking the appropriate database initialization strategy for our specific needs: CreateDatabaseIfNotExists, DropCreateDatabaseIfModelChanges, DropCreateDatabaseAlways, and MigrateDatabaseToLatestVersion. Additionally, if we need to address specific requirements, we could also set up our own custom initializer by extending one of the preceding options and overriding their core methods.

The major flaw of DbInitializers was that they were not that immediate and streamlined for the average developer. They were viable, yet difficult to handle without an extensive knowledge of the whole EF logic.

In EF Core the pattern has been greatly simplified: there are no DbInitializers and automatic migrations have also been removed. The database initialization aspect is now entirely handled through PowerShell commands, with the sole exception of a small set of commands that can be placed directly on the DbContext implementation constructor to partially automatize the process:

  • Database.EnsureCreated()
  • Database.EnsureDeleted()
  • Database.Migrate()

There's currently no way to create migrations programmatically, they must be added via PowerShell, as we're going to do shortly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset