You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
abp/docs/en/Entity-Framework-Core-Migra...

7.8 KiB

EF Core Code First Migrations

Entity Framework Core provides an easy to use and powerful database migration system. ABP Framework startup templates take the advantage of this system to allow you to develop your application in a standard way.

See its own documentation to understand the EF Core Code First Migrations and why you need to such a system.

However, EF Core migration system is not so good in a modular environment where each module maintains its own database schema while two or more modules may share a single database in practical.

Since ABP Framework cares about modularity in all aspects, it provides a solution to this problem. It is important to understand this solution if you need to customize your database structure.

This document begins by introducing the default structure provided by the application startup template and discusses various scenarios you may want to implement for your own application.

The Default Solution & Database Configuration

When you create a new web application (with EF Core, which is the default database provider), your solution structure will be similar to the picture below:

bookstore-visual-studio-solution-v3

Actual solution structure may be a bit different based on your preferences, but the database part will be same.

The Database Structure

The startup template has some application modules pre-installed. Each layer of the solution has corresponding module package references. So, the .EntityFrameworkCore project has the NuGet references for the .EntityFrameworkCore packages of the used modules:

bookstore-efcore-dependencies

In this way, you collect all the EF Core dependencies under the .EntityFrameworkCore project.

In addition to the module references, it references to the Volo.Abp.EntityFrameworkCore.SqlServer package since the startup template is pre-configured for the SQL Server. See the documentation if you want to switch to another DBMS.

While every module has its own DbContext class by design and can use its own physical database, the solution is configured to use a single shared database as shown in the figure below:

single-database-usage

This is the simplest configuration and suitable for most of the applications. appsettings.json file has a single connection string, named Default:

"ConnectionStrings": {
  "Default": "..."
}

So, you have a single database schema which contains all the tables of the modules sharing this database.

ABP Framework's connection string system allows you to easily set a different connection string for a desired module:

"ConnectionStrings": {
  "Default": "...",
  "AbpAuditLogging": "..."
}

The example configuration about tells to the ABP Framework to use the second connection string for the Audit Logging module.

However, this is just the beginning. You also need to create the second database, create audit log tables inside it and maintain the database tables using the code first approach. One of the main purposes of this document is to guide you on such database separation scenarios.

Module Tables

Every module uses its own databases tables. For example, the Identity Module has some tables to manage the users and roles in the system.

Table Prefixes

Since it is allowed to share a single database by all modules (it is the default configuration), a module typically uses a prefix to group its own tables.

The fundamental modules, like Identity, Tenant Management and Audit Logs, use the Abp prefix, while some other modules use their own prefixes. Identity Server module uses the IdentityServer prefix for example.

If you want, you can change the database table name prefix for a module for your application. Example:

Volo.Abp.IdentityServer.AbpIdentityServerDbProperties.DbTablePrefix = "Ids";

This code changes the prefix of the Identity Server module. Write this code at the very beginning in your application.

Every module also defines DbSchema property (near to DbTablePrefix), so you can set it for the databases support the schema usage.

The Projects

From the database point of view, there are three important projects those will be explained in the next sections.

.EntityFrameworkCore Project

This project has the DbContext class (BookStoreDbContext for this sample) of your application. You typically use this DbContext in your application code (in your custom repositories if you follow the best practices).

It is almost an empty DbContext since your application don't have any entities at the beginning, except the pre-defined AppUser entity:

[ConnectionStringName("Default")]
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
    public DbSet<AppUser> Users { get; set; }

    /* Add DbSet properties for your Aggregate Roots / Entities here. */

    public BookStoreDbContext(DbContextOptions<BookStoreDbContext> options)
        : base(options)
    {

    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        /* Configure the shared tables (with included modules) here */

        builder.Entity<AppUser>(b =>
        {
            //Sharing the same table "AbpUsers" with the IdentityUser
            b.ToTable("AbpUsers"); 
            
            //Configure base properties
            b.ConfigureByConvention();
            b.ConfigureAbpUser();

            //Moved customization of the "AbpUsers" table to an extension method
            b.ConfigureCustomUserProperties();
        });

        /* Configure your own tables/entities inside the ConfigureBookStore method */
        builder.ConfigureBookStore();
    }
}

This simple DbContext class still needs some explanations:

  • It defines a [ConnectionStringName] attribute which tells ABP to always use the Default connection string for this Dbcontext.
  • It inherits from the AbpDbContext<T> instead of the standard DbContext class. You can see the EF Core integration document for more. For now, know that the AbpDbContext<T> base class implements some conventions of the ABP Framework to automate some common tasks for you.
  • It declares a DbSet property for the AppUser entity. AppUser shares the same table (named AbpUsers by default) with the IdentityUser entity of the Identity module. The startup template provides this entity inside the application since we think that the User entity is generally needs to be customized in your application.
  • The constructor takes a DbContextOptions<T> instance.
  • It overrides the OnModelCreating method to define the EF Core mappings.
    • It first calls the the base.OnModelCreating method to let the ABP Framework to implement the base mappings for us.
    • It then configures the mapping for the AppUser entity. There is a special case for this entity, which will be explained in the next sections.
    • It finally calls the builder.ConfigureBookStore() extension method to configure other entities of your application.

This design will be explained in more details after introducing the other database related projects.

.EntityFrameworkCore.DbMigrations Project

TODO