From 0a7dbda5b072178bec5219f9d46370d446df5b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87otur?= Date: Mon, 5 Jul 2021 18:37:10 +0300 Subject: [PATCH 01/13] update todo-app tutorial ref ( #9284 ) --- docs/en/Tutorials/Todo/Index.md | 16 +++++++++++----- .../Tutorials/Todo/todo-efcore-migration.png | Bin 9490 -> 7122 bytes 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/en/Tutorials/Todo/Index.md b/docs/en/Tutorials/Todo/Index.md index 64cbca13f3..9f4a33a9c0 100644 --- a/docs/en/Tutorials/Todo/Index.md +++ b/docs/en/Tutorials/Todo/Index.md @@ -151,13 +151,19 @@ Open the `TodoAppDbContext` class in the `EntityFrameworkCore` folder of the *To public DbSet TodoItems { get; set; } ```` -Then open the `TodoAppDbContextModelCreatingExtensions` class in the same folder and add a mapping configuration for the `TodoItem` class as shown below: +Then locate to `OnModelCreating` method in the `TodoAppDbContext` class and add the mapping code for the `TodoItem ` entity: ````csharp -public static void ConfigureTodoApp(this ModelBuilder builder) +protected override void OnModelCreating(ModelBuilder builder) { - Check.NotNull(builder, nameof(builder)); + base.OnModelCreating(builder); + /* Include modules to your migration db context */ + + builder.ConfigurePermissionManagement(); + ... + + /* Configure your own tables/entities inside here */ builder.Entity(b => { b.ToTable("TodoItems"); @@ -171,7 +177,7 @@ We've mapped `TodoItem` entity to a `TodoItems` table in the database. The startup solution is configured to use Entity Framework Core [Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations). Since we've changed the database mapping configuration, we should create a new migration and apply changes to the database. -Open a command-line terminal in the directory of the *TodoApp.EntityFrameworkCore.DbMigrations* project and type the following command: +Open a command-line terminal in the directory of the *TodoApp.EntityFrameworkCore* project and type the following command: ````bash dotnet ef migrations add Added_TodoItem @@ -187,7 +193,7 @@ You can apply changes to the database using the following command, in the same c dotnet ef database update ```` -> If you are using Visual Studio, you may want to use `Add-Migration Added_TodoItem` and `Update-Database` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`TodoApp.Web`{{else if UI=="BlazorServer"}}`TodoApp.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`TodoApp.HttpApi.Host`{{end}} is the startup project and `TodoApp.EntityFrameworkCore.DbMigrations` is the *Default Project* in PMC. +> If you are using Visual Studio, you may want to use `Add-Migration Added_TodoItem` and `Update-Database` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`TodoApp.Web`{{else if UI=="BlazorServer"}}`TodoApp.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`TodoApp.HttpApi.Host`{{end}} is the startup project and `TodoApp.EntityFrameworkCore` is the *Default Project* in PMC. {{else if DB=="Mongo"}} diff --git a/docs/en/Tutorials/Todo/todo-efcore-migration.png b/docs/en/Tutorials/Todo/todo-efcore-migration.png index df370aebcf44b25ad02ab77df496cc6790690f72..9fffeb716b28b0469976071f38492ed17d03dd51 100644 GIT binary patch literal 7122 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 K2UY^L4EulYZ34{z literal 9490 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 Date: Mon, 5 Jul 2021 18:48:42 +0300 Subject: [PATCH 02/13] update startup-templates/application documentation ref ( #9284 ) --- docs/en/Startup-Templates/Application.md | 18 ++---------------- .../bookstore-visual-studio-solution-v3.png | Bin 12919 -> 10806 bytes 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/docs/en/Startup-Templates/Application.md b/docs/en/Startup-Templates/Application.md index 81f0170e59..1fdf980ddc 100644 --- a/docs/en/Startup-Templates/Application.md +++ b/docs/en/Startup-Templates/Application.md @@ -128,20 +128,6 @@ This is the integration project for the EF Core. It defines the `DbContext` and > This project is available only if you are using EF Core as the database provider. If you select another database provider, its name will be different. -#### .EntityFrameworkCore.DbMigrations Project - -Contains EF Core database migrations for the solution. It has a separated `DbContext` to dedicated to manage migrations. - -ABP is a modular framework and with an ideal design, each module has its own `DbContext` class. This is where the migration `DbContext` comes into play and unifies all `DbContext` configurations into a single model to maintain a single database schema. For more advanced scenarios, you can have multiple databases (each contains a single or a few module tables) and multiple migration `DbContext`s (each maintains a different database schema). - -Notice that the migration `DbContext` is only used for database migrations and *not used on runtime*. - -* Depends on the `.EntityFrameworkCore` project since it re-uses the configuration defined for the `DbContext` of the application. - -> This project is available only if you are using EF Core as the database provider. -> -> See the [Entity Framework Core Migrations Guide](../Entity-Framework-Core-Migrations.md) to understand this project in details. - #### .DbMigrator Project This is a console application which simplifies to execute database migrations on development and production environments. When you run this application, it; @@ -156,7 +142,7 @@ Especially, seeding initial data is important at this point. ABP has a modular d While creating database & applying migrations seems only necessary for relational databases, this projects comes even if you choose a NoSQL database provider (like MongoDB). In that case, it still seeds initial data which is necessary for the application. -* Depends on the `.EntityFrameworkCore.DbMigrations` project (for EF Core) since it needs to access to the migrations. +* Depends on the `.EntityFrameworkCore` project (for EF Core) since it needs to access to the migrations. * Depends on the `.Application.Contracts` project to be able to access permission definitions, because initial data seeder grants all permissions for the admin role by default. #### .HttpApi Project @@ -187,7 +173,7 @@ This project contains the main `appsettings.json` file that contains the connect * Depends on the `.HttpApi` since UI layer needs to use APIs and application service interfaces of the solution. -> If you check the source code of the `.Web.csproj` file, you will see the references to the `.Application` and the `.EntityFrameworkCore.DbMigrations` projects. +> If you check the source code of the `.Web.csproj` file, you will see the references to the `.Application` and the `.EntityFrameworkCore` projects. > > These references are actually not needed while coding your UI layer, because UI layer normally doesn't depend on the EF Core or the Application layer's implementation. This startup templates are ready for the tiered deployment, where API layer is hosted in a separate server than the UI layer. > diff --git a/docs/en/images/bookstore-visual-studio-solution-v3.png b/docs/en/images/bookstore-visual-studio-solution-v3.png index 307e3516a5414173016efaedd22e53983fa25f1c..f8ef7f2ba0de7b671baff05c3f4de5fbdc0d09e7 100644 GIT binary patch literal 10806 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 Y`=8bhBcTZRt>>bBP6r)n4#zJ1AGaTv`~Uy| literal 12919 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 From e92bb104e49f6fa902ea53088ac0e7d3d2059e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87otur?= Date: Tue, 6 Jul 2021 10:47:15 +0300 Subject: [PATCH 03/13] Update Entity-Framework-Core-Other-DBMS.md ref ( #9284 ) --- docs/en/Entity-Framework-Core-Other-DBMS.md | 26 +++++---------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/docs/en/Entity-Framework-Core-Other-DBMS.md b/docs/en/Entity-Framework-Core-Other-DBMS.md index d9190df844..8c9078583d 100644 --- a/docs/en/Entity-Framework-Core-Other-DBMS.md +++ b/docs/en/Entity-Framework-Core-Other-DBMS.md @@ -62,20 +62,18 @@ MySQL connection strings are different than SQL Server connection strings. So, c You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure. -## Change the Migrations DbContext +## DBMS restrictions MySQL DBMS has some slight differences than the SQL Server. Some module database mapping configuration (especially the field lengths) causes problems with MySQL. For example, some of the the [IdentityServer module](Modules/IdentityServer.md) tables has such problems and it provides an option to configure the fields based on your DBMS. -The startup template contains a *YourProjectName*MigrationsDbContext which is responsible to maintain and migrate the database schema. This DbContext basically calls extension methods of the depended modules to configure their database tables. - -Open the *YourProjectName*MigrationsDbContext and change the `builder.ConfigureIdentityServer();` line as shown below: +The module may provide some built-in solutions. You can configure it via `ModelBuilder`. eg: `Identity Server` module. -````csharp +```csharp builder.ConfigureIdentityServer(options => { options.DatabaseProvider = EfCoreDatabaseProvider.MySql; }); -```` +``` Then `ConfigureIdentityServer()` method will set the field lengths to not exceed the MySQL limits. Refer to related module documentation if you have any problem while creating or executing the database migrations. @@ -83,8 +81,8 @@ Then `ConfigureIdentityServer()` method will set the field lengths to not exceed The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails. -* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. -* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). +* Delete the Migrations folder under the `.EntityFrameworkCore` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore` project as the default project in the Package Manager Console). This will create a database migration with all database objects (tables) configured. @@ -94,16 +92,4 @@ Run the `.DbMigrator` project to create the database and seed the initial data. It is ready. Just run the application and enjoy coding. -## DBMS restrictions - -Different DBMS may have some restrictions, such as the maximum length of field names, index length, etc. -The module may provide some built-in solutions. You can configure it via `ModelBuilder`. eg: `Identity Server` module. - -```csharp -builder.ConfigureIdentityServer(options => -{ - options.DatabaseProvider = EfCoreDatabaseProvider.MySql; -}); -``` - Related discussions: https://github.com/abpframework/abp/issues/1920 \ No newline at end of file From a8eccb2f4671cf3e89fb1a503122d7e60dfe0158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87otur?= Date: Tue, 6 Jul 2021 10:56:29 +0300 Subject: [PATCH 04/13] update Entity-Framework-Core-* docs ref ( #9284 ) --- docs/en/Entity-Framework-Core-MySQL.md | 6 +++--- docs/en/Entity-Framework-Core-Oracle-Devart.md | 6 +++--- docs/en/Entity-Framework-Core-Oracle-Official.md | 6 +++--- docs/en/Entity-Framework-Core-PostgreSQL.md | 6 +++--- docs/en/Entity-Framework-Core-SQLite.md | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/en/Entity-Framework-Core-MySQL.md b/docs/en/Entity-Framework-Core-MySQL.md index 14f419557e..53469e95d9 100644 --- a/docs/en/Entity-Framework-Core-MySQL.md +++ b/docs/en/Entity-Framework-Core-MySQL.md @@ -15,7 +15,7 @@ Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFra Find `UseSqlServer()` calls in your solution. Check the following files: * *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. Replace `UseSqlServer()` with `UseMySQL()`. -* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project. Replace `UseSqlServer()` with `UseMySql()`. Then add a new parameter (`ServerVersion`) to `UseMySql()` method. Example: `.UseMySql(configuration.GetConnectionString("Default"), ServerVersion.FromString("8.0.21-mysql"))`. See [this issue](https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/pull/1233) for more information about `ServerVersion`) +* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project. Replace `UseSqlServer()` with `UseMySql()`. Then add a new parameter (`ServerVersion`) to `UseMySql()` method. Example: `.UseMySql(configuration.GetConnectionString("Default"), ServerVersion.FromString("8.0.21-mysql"))`. See [this issue](https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/pull/1233) for more information about `ServerVersion`) > Depending on your solution structure, you may find more code files need to be changed. @@ -29,8 +29,8 @@ You typically will change the `appsettings.json` inside the `.DbMigrator` and `. The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails. -* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. -* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). +* Delete the Migrations folder under the `.EntityFrameworkCore` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore` project as the default project in the Package Manager Console). This will create a database migration with all database objects (tables) configured. diff --git a/docs/en/Entity-Framework-Core-Oracle-Devart.md b/docs/en/Entity-Framework-Core-Oracle-Devart.md index 23e660378c..96f02714ab 100644 --- a/docs/en/Entity-Framework-Core-Oracle-Devart.md +++ b/docs/en/Entity-Framework-Core-Oracle-Devart.md @@ -19,7 +19,7 @@ Also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Ab Find `UseSqlServer()` calls in your solution, replace with `UseOracle()`. Check the following files: * *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. -* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project. +* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project. In the `CreateDbContext()` method of the *YourProjectName*MigrationsDbContextFactory.cs, replace the following code block @@ -51,8 +51,8 @@ You typically will change the `appsettings.json` inside the `.DbMigrator` and `. The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/) by default. EF Core Migrations depend on the selected DBMS provider. Changing the DBMS provider, may not work with the existing migrations. -* Delete the `Migrations` folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. -* Run `Add-Migration "Initial"` on the Package Manager Console window (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). +* Delete the `Migrations` folder under the `.EntityFrameworkCore` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console window (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore` project as the default project in the Package Manager Console). This will scaffold a new migration for Oracle. diff --git a/docs/en/Entity-Framework-Core-Oracle-Official.md b/docs/en/Entity-Framework-Core-Oracle-Official.md index 8ae1a1bac0..aab71c9e59 100644 --- a/docs/en/Entity-Framework-Core-Oracle-Official.md +++ b/docs/en/Entity-Framework-Core-Oracle-Official.md @@ -17,7 +17,7 @@ Also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Ab Find `UseSqlServer()` calls in your solution, replace with `UseOracle()`. Check the following files: * *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. -* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project. +* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project. In the `CreateDbContext()` method of the *YourProjectName*MigrationsDbContextFactory.cs, replace the following code block @@ -46,8 +46,8 @@ You typically will change the `appsettings.json` inside the `.DbMigrator` and `. The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/) by default. EF Core Migrations depend on the selected DBMS provider. Changing the DBMS provider, may not work with the existing migrations. -* Delete the `Migrations` folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. -* Run `Add-Migration "Initial"` on the Package Manager Console window (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). +* Delete the `Migrations` folder under the `.EntityFrameworkCore` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console window (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore` project as the default project in the Package Manager Console). This will scaffold a new migration for Oracle. diff --git a/docs/en/Entity-Framework-Core-PostgreSQL.md b/docs/en/Entity-Framework-Core-PostgreSQL.md index 4c6099b809..a8dbdc7b67 100644 --- a/docs/en/Entity-Framework-Core-PostgreSQL.md +++ b/docs/en/Entity-Framework-Core-PostgreSQL.md @@ -15,7 +15,7 @@ Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFra Find `UseSqlServer()` call in *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project and replace with `UseNpgsql()`. -Find `UseSqlServer()` call in *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project and replace with `UseNpgsql()`. +Find `UseSqlServer()` call in *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project and replace with `UseNpgsql()`. > Depending on your solution structure, you may find more `UseSqlServer()` calls that needs to be changed. @@ -29,8 +29,8 @@ You typically will change the `appsettings.json` inside the `.DbMigrator` and `. The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails. -* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. -* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). +* Delete the Migrations folder under the `.EntityFrameworkCore` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore` project as the default project in the Package Manager Console). This will create a database migration with all database objects (tables) configured. diff --git a/docs/en/Entity-Framework-Core-SQLite.md b/docs/en/Entity-Framework-Core-SQLite.md index 2a13bf530c..bcd6c6d927 100644 --- a/docs/en/Entity-Framework-Core-SQLite.md +++ b/docs/en/Entity-Framework-Core-SQLite.md @@ -15,7 +15,7 @@ Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFra Find `UseSqlServer()` calls in your solution, replace with `UseSqlite()`. Check the following files: * *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. -* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project. +* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project. > Depending on your solution structure, you may find more code files need to be changed. @@ -39,8 +39,8 @@ You typically will change the `appsettings.json` inside the `.DbMigrator` and `. The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails. -* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. -* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). +* Delete the Migrations folder under the `.EntityFrameworkCore` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore` project as the default project in the Package Manager Console). This will create a database migration with all database objects (tables) configured. From f1c2e49407770bc5de7e94a3fbc0463b5dc76731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87otur?= Date: Tue, 6 Jul 2021 10:59:51 +0300 Subject: [PATCH 05/13] Update Connection-Strings.md ref ( #9284 ) --- docs/en/Connection-Strings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Connection-Strings.md b/docs/en/Connection-Strings.md index 585d0657f2..c5a70174bf 100644 --- a/docs/en/Connection-Strings.md +++ b/docs/en/Connection-Strings.md @@ -70,7 +70,7 @@ For [Entity Framework Core](Entity-Framework-Core.md) and [MongoDB](MongoDB.md), Relational databases require to create the database and the database schema (tables, views... etc.) before using it. -The startup template (with EF Core ORM) comes with a single database and a `.EntityFrameworkCore.DbMigrations` project that contains the migration files for that database. This project mainly defines a *YourProjectName*MigrationsDbContext that calls the `Configure...()` methods of the used modules, like `builder.ConfigurePermissionManagement()`. +The startup template (with EF Core ORM) comes with a single database and a `.EntityFrameworkCore` project that contains related classes and the migration files for that database. This project mainly defines a *YourProjectName*DbContext that calls the `Configure...()` methods of the used modules, like `builder.ConfigurePermissionManagement()`. Once you want to separate a module's database, you typically will need to create a second migration path. See the [EF Core Migrations](Entity-Framework-Core-Migrations.md) document to learn how to create and use a different database for a desired module. From 4347075c633b65592aa19e77af4efceec395ef72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87otur?= Date: Tue, 6 Jul 2021 11:00:59 +0300 Subject: [PATCH 06/13] Update Upgrading.md ref ( #9284 ) --- docs/en/Upgrading.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Upgrading.md b/docs/en/Upgrading.md index 9c4e39ce7e..2141a6823b 100644 --- a/docs/en/Upgrading.md +++ b/docs/en/Upgrading.md @@ -22,7 +22,7 @@ Run this command in the terminal while you are in the root folder of your soluti When you upgrade to a new version, it is good to check if there is a database schema change and upgrade your database schema if your database provider is **Entity Framework Core**; -* Use `Add-Migration "Upgraded_To_Abp_4_1"` or a similar command in the Package Manager Console (PMC) to create a new migration (Set the `EntityFrameworkCore.DbMigrations` as the Default project in the PMC and `.DbMigrator` as the Startup Project in the Solution Explorer, in the Visual Studio). +* Use `Add-Migration "Upgraded_To_Abp_4_1"` or a similar command in the Package Manager Console (PMC) to create a new migration (Set the `EntityFrameworkCore` as the Default project in the PMC and `.DbMigrator` as the Startup Project in the Solution Explorer, in the Visual Studio). * Run the `.DbMigrator` application to upgrade the database and seed the initial data. If `Add-Migration` generates an empty migration, you can use `Remove-Migration` to delete it before executing the `.DbMigrator`. From e01ffd32c32095de13469e1ab4f0eba323a76c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87otur?= Date: Tue, 6 Jul 2021 11:02:37 +0300 Subject: [PATCH 07/13] Update CLI-New-Command-Samples.md ref ( #9284 ) --- docs/en/CLI-New-Command-Samples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/CLI-New-Command-Samples.md b/docs/en/CLI-New-Command-Samples.md index e6c6f64ead..9eae987925 100644 --- a/docs/en/CLI-New-Command-Samples.md +++ b/docs/en/CLI-New-Command-Samples.md @@ -217,7 +217,7 @@ As seen below, ABP Framework libraries are local project references. - + ``` From 9637b6478815d5f5a563d88140769fa459e59cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87otur?= Date: Tue, 6 Jul 2021 11:07:28 +0300 Subject: [PATCH 08/13] update docs documentation ref ( #9284 ) --- docs/en/Modules/Docs.md | 8 ++++---- .../images/docs-module_solution-explorer.png | Bin 21497 -> 11249 bytes 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en/Modules/Docs.md b/docs/en/Modules/Docs.md index 129317a7d8..4c764ee2c6 100644 --- a/docs/en/Modules/Docs.md +++ b/docs/en/Modules/Docs.md @@ -38,7 +38,7 @@ Note that this document covers `Entity Framework Core` provider but you can also ### 2- Running The Empty Application -After you download the project, extract the ZIP file and open `Acme.MyProject.sln`. You will see that the solution consists of `Application`, `Application.Contracts`, `DbMigrator`, `Domain`, `Domain.Shared`, `EntityFrameworkCore`, `EntityFrameworkCore.DbMigations`, `HttpApi`, `HttpApi.Client` and `Web` projects. Right click on `Acme.MyProject.Web` project and **Set as StartUp Project**. +After you download the project, extract the ZIP file and open `Acme.MyProject.sln`. You will see that the solution consists of `Application`, `Application.Contracts`, `DbMigrator`, `Domain`, `Domain.Shared`, `EntityFrameworkCore`, `HttpApi`, `HttpApi.Client` and `Web` projects. Right click on `Acme.MyProject.Web` project and **Set as StartUp Project**. ![Create a new project](../images/docs-module_solution-explorer.png) @@ -237,15 +237,15 @@ If you choose Entity Framework as your database provider, you need to configure } ``` -* Open `Package Manager Console` in `Visual Studio` and choose `Acme.MyProject.EntityFrameworkCore.DbMigrations` as default project. Then write the below command to add the migration for Docs Module. +* Open `Package Manager Console` in `Visual Studio` and choose `Acme.MyProject.EntityFrameworkCore` as default project. Then write the below command to add the migration for Docs Module. ```csharp add-migration Added_Docs_Module ``` - When the command successfully executes , you will see a new migration file named as `20181221111621_Added_Docs_Module` in the folder `Acme.MyProject.EntityFrameworkCore.DbMigrations\Migrations`. + When the command successfully executes , you will see a new migration file named as `20181221111621_Added_Docs_Module` in the folder `Acme.MyProject.EntityFrameworkCore\Migrations`. - Now, update the database for Docs module database changes. To do this run the below code on `Package Manager Console` in `Visual Studio`. Be sure `Acme.MyProject.EntityFrameworkCore.DbMigrations` is still default project. + Now, update the database for Docs module database changes. To do this run the below code on `Package Manager Console` in `Visual Studio`. Be sure `Acme.MyProject.EntityFrameworkCore` is still default project. ```csharp update-database diff --git a/docs/en/images/docs-module_solution-explorer.png b/docs/en/images/docs-module_solution-explorer.png index 2988ec41342e7d4528373d7559e390f6e29c41a9..42b2c3114333e1d7e2d3a3b65570ce0aee24bf39 100644 GIT binary patch literal 11249 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 Date: Tue, 6 Jul 2021 11:12:29 +0300 Subject: [PATCH 09/13] Update How-To-Add-Custom-Property-To-The-User-Entity.md ref ( #9284 ) --- .../How-To-Add-Custom-Property-To-The-User-Entity.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md b/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md index 80141a32fe..308358bb67 100644 --- a/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md +++ b/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md @@ -101,7 +101,7 @@ Now we need to add migration to see what has changed in our database. This for, ![nuget-package-manager](./nuget-package-manager.png) -Select the **CustomizeUserDemo.EntityFramework.DbMigrations** as the **default project** and execute the following command: +Select the **CustomizeUserDemo.EntityFramework** as the **default project** and execute the following command: ```bash Add-Migration "Updated-User-Entity" @@ -109,7 +109,7 @@ Add-Migration "Updated-User-Entity" ![added-new-migration](./added-new-migration.png) -This will create a new migration class inside the `Migrations` folder of the **CustomizeUserDemo.EntityFrameworkCore.DbMigrations** project. +This will create a new migration class inside the `Migrations` folder of the **CustomizeUserDemo.EntityFrameworkCore** project. > If you are using another IDE than the Visual Studio, you can use `dotnet-ef` tool as [documented here](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli#create-a-migration). From 65662770f773e70297be7658632d6c5a62847b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87otur?= Date: Tue, 6 Jul 2021 11:14:45 +0300 Subject: [PATCH 10/13] Update initial-project.png ref ( #9284 ) --- .../initial-project.png | Bin 24691 -> 10832 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/initial-project.png b/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/initial-project.png index 6e088338533fa9c01108417e3253b497a812c4e9..b64e93a99fea09b23724ac9266e49e4925ba9414 100755 GIT binary patch literal 10832 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 literal 24691 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

)wBntkoa6)q5)UVkZj)Sa z$ftOU`Gb*i#|5PK8#wW=iS1n~ry-TH$4%YfIxjA6W*I8nl=lMTeZ->4AkoZ6D@j@J z1e9Aw?p?{w))%%z&~t_i*f;@u(Z)Ps%1j+3^+YWBshr>=I#pbyHls27HBRq}(gD}j z?xx=Gy4>(8SOa47NA9CLc5Ny~2Mv`8MAV80v?E+y$Z4odUx48eZDpsBDm>C9YD9}5 zZs_XDMZZ^5YoO;EJNT=zN-_C3d{iGEpYU91Z5qEL0N2r-tr@W`+dv_xa_*5dS_+Qikicbiko;}x-UTplAkfXNar9!MhTddOz=Ezb zwDd@+a|yhs%IVf=F}DbVFGPc6YNi#z8@t7;D*b%s+STiweiB=;NkG4cA&pWWwxUgi zouZBkJ|ifmPv^!`?#`B_3=W#vHo(UQ*t>B&^>Mu*x^8gUBdSEy97QRBHib|wv+y+F zoInoXBX|Q&@7V#}FxIw!`I*5nT>J0>!`$YcL*uArl#Y@vlfKIO-drM|;z!dgMDW^C zO6gM$Bp^7PlQx*2uBdtCBl`e7CMkEse61_;&g^+HsgpGv&9}dS3ViK#SGGKL5_nZX zhv$yDU~Y&T2PdvUm@zU-zlJQX$G#iTveE;?8=il@`rgUaFSFfO z{0Uw(KKza}6-Jv_0*wxmLFnK~N2a%ycH@2d3Y-K%0ccpPvWu`W`gt)nNOR^baBGrU;6Im3ejfFY| z9-`)MQ8!&a)ds(|y@uwr?5k?8SyTkAI8SP{&zEv<2C+DAy(?qfG)2fzwl(V6r5nO{ z(qlrJ=zx!ds`5^u0ON7T$0ExB@ryZI#cbp?{GM)g8N7jsZjPbNZvY+acoS~K)YB>K z@c08J8eW3#Sfg%t4{N4O7z2p+)8i~>Xu~a_z@D$Cbn+_;^(RZI=fLwUl$Yg{O}v|7 zm){S9tcy+E8|Jn)?F_|WsWgdqhe%Vib&nh+KMWUh(Uxb3aDKlqmwgRqR=&`Ynp0s- zSEY>~>$*4`SMHqgJ^vk-t-7^j99n!L@(3sP{rIgy0u9!4*MRNUlY2z$`d+tKuO5&< zpH2v$oy63b2JG(Q z>lUE<9^R3+kucl0MFKN74)7hHm5Ha@>nLFz4>mXMPN%k`tmj?hs30evw!kNift`_HTtdr=C#gz?x) zA40VPGlHG*np-7pQs?V!#?)(d0sPBhHy5X2ydM3=XZZxIvbd~=jrN$ny0mwQfWsqR zS=0(Ms|dMf%X=qtykJq2rf?np%+~YP)Fsl~@!|f1`RIwuB?Ry$}8UCos-*n^xz zF@EMZb@DPQlij(iAfxB`9A#w@P5O4#-R7>AEwGMzmhTedF9lBqrQ5zy6Fe9&&mKHY zQYg_H6IcTb3^CO2%#^L=ggU?i1<2|H_@mv`#T+h1BSH~Y*0(^N)p8;1h@gna^;xt5 zpb~akGbQcNb9q;Y9fzm0KNCjNk#ogAly Date: Tue, 6 Jul 2021 13:20:03 +0300 Subject: [PATCH 11/13] Update Entity-Framework-Core-Migrations.md ref ( #9284 ) --- docs/en/Entity-Framework-Core-Migrations.md | 203 +------------------- 1 file changed, 8 insertions(+), 195 deletions(-) diff --git a/docs/en/Entity-Framework-Core-Migrations.md b/docs/en/Entity-Framework-Core-Migrations.md index 4d42d8bb97..254431a434 100644 --- a/docs/en/Entity-Framework-Core-Migrations.md +++ b/docs/en/Entity-Framework-Core-Migrations.md @@ -87,7 +87,7 @@ This code changes the prefix of the [Identity Server](Modules/IdentityServer.md) ### The Projects -From the database point of view, there are three important projects those will be explained in the next sections. +From the database point of view, there is one important project that will be explained in the next sections. #### .EntityFrameworkCore Project @@ -147,56 +147,9 @@ This simple `DbContext` class still needs some explanations: This design will be explained in more details after introducing the other database related projects. -#### .EntityFrameworkCore.DbMigrations Project - -As mentioned in the previous section, every module (and your application) have **their own** separate `DbContext` classes. Each `DbContext` class only defines the entity to table mappings related to its own module and each module (and your application) use the related `DbContext` class **on runtime**. - -As you know, EF Core Code First migration system relies on a `DbContext` class **to track and generate** the code first migrations. So, which `DbContext` we should use for the migrations? The answer is *none of them*. There is another `DbContext` defined in the `.EntityFrameworkCore.DbMigrations` project (which is the `BookStoreMigrationsDbContext` for this example solution). - -##### The MigrationsDbContext - -The `MigrationsDbContext` is only used to create and apply the database migrations. It is **not used on runtime**. It **merges** all the entity to table mappings of all the used modules plus the application's mappings. - -In this way, you create and maintain a **single database migration path**. However, there are some difficulties of this approach and the next sections explains how ABP Framework overcomes these difficulties. But first, see the `BookStoreMigrationsDbContext` class as an example: - -````csharp -/* This DbContext is only used for database migrations. - * It is not used on runtime. See BookStoreDbContext for the runtime DbContext. - * It is a unified model that includes configuration for - * all used modules and your application. - */ -public class BookStoreMigrationsDbContext : AbpDbContext -{ - public BookStoreMigrationsDbContext( - DbContextOptions options) - : base(options) - { - - } - - protected override void OnModelCreating(ModelBuilder builder) - { - base.OnModelCreating(builder); - - /* Include modules to your migration db context */ - builder.ConfigurePermissionManagement(); - builder.ConfigureSettingManagement(); - builder.ConfigureBackgroundJobs(); - builder.ConfigureAuditLogging(); - builder.ConfigureIdentity(); - builder.ConfigureIdentityServer(); - builder.ConfigureFeatureManagement(); - builder.ConfigureTenantManagement(); - - /* Configure your own tables/entities inside the ConfigureBookStore method */ - builder.ConfigureBookStore(); - } -} -```` - ##### Sharing the Mapping Code -First problem is that: A module uses its own `DbContext` which needs to the database mappings. The `MigrationsDbContext` also needs to the same mapping in order to create the database tables for this module. We definitely **don't want to duplicate** the mapping code. +First problem is that: A module uses its own `DbContext` which needs to the database mappings. The `ApplicationDbContext` also needs to the same mapping in order to create the database tables for this module. We definitely **don't want to duplicate** the mapping code. The solution is to define an **extension method** (on the `ModelBuilder`) that can be called by both `DbContext` classes. So, all modules define such extension methods. @@ -235,7 +188,7 @@ public static class BackgroundJobsDbContextModelCreatingExtensions This extension method also gets options to change the database table prefix and schema for this module, but it is not important here. -The final application calls the extension methods inside the `MigrationsDbContext` class, so it can decide which modules are included in the database maintained by this `MigrationsDbContext`. If you want to create a second database and move some module tables to the second database, then you need to have a second `MigrationsDbContext` class which only calls the extension methods of the related modules. This topic will be detailed in the next sections. +The final application calls the extension methods inside the `ApplicationDbContext` class, so it can decide which modules are included in the database maintained by this `ApplicationDbContext`. If you want to create a second database and move some module tables to the second database, then you need to have a second `ApplicationDbContext` class which only calls the extension methods of the related modules. This topic will be detailed in the next sections. The same `ConfigureBackgroundJobs` method is also called in the `DbContext` of the Background Jobs module: @@ -430,7 +383,7 @@ See the [EF Core integration documentation](Entity-Framework-Core.md) for more a > We've repeated a similar database mapping code, like `HasMaxLength(128)`, in both classes. -Now, you can add a new EF Core database migration using the standard `Add-Migration` command in the Package Manager Console (remember to select `.EntityFrameworkCore.DbMigrations` as the Default Project in the PMC and make sure that the `.Web` project is still the startup project): +Now, you can add a new EF Core database migration using the standard `Add-Migration` command in the Package Manager Console (remember to select `.EntityFrameworkCore` as the Default Project in the PMC and make sure that the `.Web` project is still the startup project): ![pmc-add-migration-role-title](images/pmc-add-migration-role-title.png) @@ -561,7 +514,7 @@ In this case, you don't deal with migration problems, however you need to deal w #### Discussion of an Alternative Scenario: Every Module Manages Its Own Migration Path -As mentioned before, `.EntityFrameworkCore.DbMigrations` merges all the database mappings of all the modules (plus your application's mappings) to create a unified migration path. +As mentioned before, `.EntityFrameworkCore` merges all the database mappings of all the modules (plus your application's mappings) to create a unified migration path. An alternative approach would be to allow each module to have its own migrations to maintain its database tables. While it seems more module in the beginning, it has some important drawbacks: @@ -605,112 +558,6 @@ Added **three more connection strings** for the related module to target the `Bo The `AbpPermissionManagement` is a constant [defined](https://github.com/abpframework/abp/blob/97eaa6ff5a044f503465455c86332e5a277b077a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDbProperties.cs#L11) by the permission management module. ABP Framework [connection string selection system](Connection-Strings.md) selects this connection string for the permission management module if you define. If you don't define, it fallbacks to the `Default` connection string. -### Create a Second Migration Project - -Defining the connection strings as explained above is enough **on runtime**. However, `BookStore_SecondDb` database doesn't exist yet. You need to create the database and the tables for the related modules. - -Just like the main database, we want to use the EF Core Code First migration system to create and maintain the second database. - -An easy way is to create a second project (`.csproj`) for the second migration `DbContext`. - -So, create a new **class library project** in your solution named `Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb` (or name it better if you didn't like it). - -The `.csproj` content should be something like that: - -````xml - - - - - - netcoreapp3.1 - Acme.BookStore.DbMigrationsForSecondDb - - - - - - - - - - - -```` - -You can just copy & modify the content of the original `.DbMigrations` project. This project references to the `.EntityFrameworkCore` project. **Only difference** is the `RootNamespace` value. - -**Add a reference** to this project from the `.Web` project (otherwise, EF Core tooling doesn't allow to use the `Add-Migration` command). - -### Create the Second DbMigrationDbContext - -Create a new `DbContext` for the migrations and call the **extension methods** of the modules to configure the database tables for the related modules: - -````csharp -[ConnectionStringName("AbpPermissionManagement")] -public class BookStoreSecondMigrationsDbContext : - AbpDbContext -{ - public BookStoreSecondMigrationsDbContext( - DbContextOptions options) - : base(options) - { - } - - protected override void OnModelCreating(ModelBuilder builder) - { - base.OnModelCreating(builder); - - /* Include modules to your migration db context */ - - builder.ConfigurePermissionManagement(); - builder.ConfigureSettingManagement(); - builder.ConfigureAuditLogging(); - } -} -```` - -> `[ConnectionStringName(...)]` attribute is important here and tells to the ABP Framework which connection string should be used for this `DbContext`. We've used `AbpPermissionManagement`, but all are the same. - -Create a **Design Time Db Factory** class, that is used by the EF Core tooling (by `Add-Migration` and `Update-Database` PCM commands for example): - -````csharp -/* This class is needed for EF Core console commands - * (like Add-Migration and Update-Database commands) */ -public class BookStoreSecondMigrationsDbContextFactory - : IDesignTimeDbContextFactory -{ - public BookStoreSecondMigrationsDbContext CreateDbContext(string[] args) - { - var configuration = BuildConfiguration(); - - var builder = new DbContextOptionsBuilder() - .UseSqlServer(configuration.GetConnectionString("AbpPermissionManagement")); - - return new BookStoreSecondMigrationsDbContext(builder.Options); - } - - private static IConfigurationRoot BuildConfiguration() - { - var builder = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: false); - - return builder.Build(); - } -} -```` - -This is similar to the class inside the `.EntityFrameworCore.DbMigrations` project, except this one uses the `AbpPermissionManagement` connection string. - -Now, you can open the Package Manager Console, select the `.EntityFrameworkCore.DbMigrationsForSecondDb` project as the default project (make sure the `.Web` project is still the startup project) and run the `Add-Migration "Initial"` and `Update-Database` commands as shown below: - -![pmc-add-migration-initial-update-database](images/pmc-add-migration-initial-update-database.png) - -Now, you should have a new database contains only the tables needed by the related modules: - -![bookstore-second-database](images/bookstore-second-database.png) - ### Remove Modules from the Main Database We've **created a second database** contains tables for the Audit Logging, Permission Management and Setting Management modules. So, we should **delete these tables from the main database**. It is pretty easy. @@ -723,7 +570,7 @@ builder.ConfigureSettingManagement(); builder.ConfigureAuditLogging(); ```` -Open the Package Manager Console, select the `.EntityFrameworkCore.DbMigrations` as the Default project (make sure that the `.Web` project is still the startup project) and run the following command: +Open the Package Manager Console, select the `.EntityFrameworkCore` as the Default project (make sure that the `.Web` project is still the startup project) and run the following command: ```` Add-Migration "Removed_Audit_Setting_Permission_Modules" @@ -774,7 +621,7 @@ Notice that you've also **deleted some initial seed data** (for example, permiss #### Implementing the IBookStoreDbSchemaMigrator -`EntityFrameworkCoreBookStoreDbSchemaMigrator` class inside the `Acme.BookStore.EntityFrameworkCore.DbMigrations` project is responsible to migrate the database schema for the `BookStoreMigrationsDbContext`. It should be like that: +`EntityFrameworkCoreBookStoreDbSchemaMigrator` class inside the `Acme.BookStore.EntityFrameworkCore` project is responsible to migrate the database schema for the `BookStoreMigrationsDbContext`. It should be like that: ````csharp [Dependency(ReplaceServices = true)] @@ -809,7 +656,7 @@ It implements the `IBookStoreDbSchemaMigrator` and **replaces existing services* Remove the `[Dependency(ReplaceServices = true)]` line, because we will have two implementations of this interface and we want to use both. We don't want to replace one of them. -Create a copy of this class inside the new migration project (`Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb`), but use the `BookStoreSecondMigrationsDbContext`. Example implementation: +Create a copy of this class inside the new migration project (`Acme.BookStore.EntityFrameworkCore.ForSecondDb`), but use the `BookStoreSecondMigrationsDbContext`. Example implementation: ````csharp public class EntityFrameworkCoreSecondBookStoreDbSchemaMigrator @@ -843,40 +690,6 @@ public class EntityFrameworkCoreSecondBookStoreDbSchemaMigrator We, now, have two implementations of the `IBookStoreDbSchemaMigrator` interface, each one responsible to migrate the related database schema. -#### Define a Module Class for the Second Migration Project - -It is time to define the [module](Module-Development-Basics.md) class for this second migrations (`Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb`) project: - -````csharp -[DependsOn( - typeof(BookStoreEntityFrameworkCoreModule) - )] -public class BookStoreEntityFrameworkCoreSecondDbMigrationsModule : AbpModule -{ - public override void ConfigureServices(ServiceConfigurationContext context) - { - context.Services.AddAbpDbContext(); - } -} -```` - -Now, reference `Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb` project from the `Acme.BookStore.DbMigrator` project and `typeof(BookStoreEntityFrameworkCoreSecondDbMigrationsModule)` to the dependency list of the `BookStoreDbMigratorModule`. `BookStoreDbMigratorModule` class should be something like that: - -````csharp -[DependsOn( - typeof(AbpAutofacModule), - typeof(BookStoreEntityFrameworkCoreDbMigrationsModule), - typeof(BookStoreEntityFrameworkCoreSecondDbMigrationsModule), // ADDED THIS! - typeof(BookStoreApplicationContractsModule) - )] -public class BookStoreDbMigratorModule : AbpModule -{ - ... -} -```` - -We had a reference to the `Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb` project from the `Acme.BookStore.Web` project, but hadn't added module dependency since we hadn't created it before. But, now we have it and we need to add `typeof(BookStoreEntityFrameworkCoreSecondDbMigrationsModule)` to the dependency list of the `BookStoreWebModule` class. - #### Run the Database Migrator! You can run the `.DbMigrator` application to migrate & seed the databases. To test, you can delete both databases and run the `.DbMigrator` application again to see if it creates both of the databases. From 0f5ccf41c6860c4b245dda1d5896aa70c4dbca92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 9 Jul 2021 10:03:23 +0300 Subject: [PATCH 12/13] Revisit the EF Core migrations document for ABP 4.4. --- docs/en/Entity-Framework-Core-Migrations.md | 681 +++++++------------- 1 file changed, 237 insertions(+), 444 deletions(-) diff --git a/docs/en/Entity-Framework-Core-Migrations.md b/docs/en/Entity-Framework-Core-Migrations.md index 254431a434..5d8ca01854 100644 --- a/docs/en/Entity-Framework-Core-Migrations.md +++ b/docs/en/Entity-Framework-Core-Migrations.md @@ -61,9 +61,9 @@ ABP Framework's [connection string](Connection-Strings.md) system allows you to } ```` -The example configuration about tells to the ABP Framework to use the second connection string for the [Audit Logging module](Modules/Audit-Logging.md). +The example configuration tells to the ABP Framework to use the second connection string for the [Audit Logging module](Modules/Audit-Logging.md) (if you don't specify connection string for a module, it uses the `Default` connection string). -**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 migrations approach. One of the main purposes of this document is to guide you on such **database separation** scenarios. +**However, this can work only if the audit log database with the given connection string is available**. So, you need to create the second database, create audit log tables inside it and maintain the database tables. No problem if you manually do all these. However, the recommended approach is the code first migrations. One of the main purposes of this document is to guide you on such **database separation** scenarios. #### Module Tables @@ -85,23 +85,24 @@ This code changes the prefix of the [Identity Server](Modules/IdentityServer.md) > Every module also defines `DbSchema` property (near to `DbTablePrefix`), so you can set it for the databases support the schema usage. -### The Projects +### .EntityFrameworkCore Project -From the database point of view, there is one important project that will be explained in the next sections. +The solution contains a project, which's name ends with `.EntityFrameworkCore`. This project has the `DbContext` class (`BookStoreDbContext` for this sample) of your application. -#### .EntityFrameworkCore Project - -This project has the `DbContext` class (`BookStoreDbContext` for this sample) of your application. - -**Every module uses its own `DbContext` class** to access to the database. Likewise, your application has its own `DbContext`. You typically use this `DbContext` in your application code (in your [repositories](Repositories.md) 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: +**Every module uses its own `DbContext` class** to access to the database. Likewise, your application has its own `DbContext`. You typically use this `DbContext` in your application code (in your [repositories](Repositories.md) if you follow the best practices and hide your data access code behind the repositories). It is almost an empty `DbContext` since your application don't have any entities at the beginning: ````csharp +[ReplaceDbContext(typeof(IIdentityDbContext))] +[ReplaceDbContext(typeof(ITenantManagementDbContext))] [ConnectionStringName("Default")] -public class BookStoreDbContext : AbpDbContext +public class BookStoreDbContext : + AbpDbContext, + IIdentityDbContext, + ITenantManagementDbContext { - public DbSet Users { get; set; } - /* Add DbSet properties for your Aggregate Roots / Entities here. */ + + /* DbSet for entities from the replaced DbContexts */ public BookStoreDbContext(DbContextOptions options) : base(options) @@ -112,457 +113,188 @@ public class BookStoreDbContext : AbpDbContext protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); - - /* Configure the shared tables (with included modules) here */ - - builder.Entity(b => - { - //Sharing the same Users table with the IdentityUser - b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users"); - - b.ConfigureByConvention(); - b.ConfigureAbpUser(); - - /* Configure mappings for your additional properties - * Also see the MyProjectNameEntityExtensions class - */ - }); - - /* Configure your own tables/entities inside the ConfigureBookStore method */ - builder.ConfigureBookStore(); + + /* Include modules to your migration db context */ + builder.ConfigurePermissionManagement(); + builder.ConfigureSettingManagement(); + builder.ConfigureBackgroundJobs(); + builder.ConfigureAuditLogging(); + builder.ConfigureIdentity(); + builder.ConfigureIdentityServer(); + builder.ConfigureFeatureManagement(); + builder.ConfigureTenantManagement(); + + /* Configure your own tables/entities here. Example: */ + //builder.Entity(b => + //{ + // b.ToTable("YourEntities"); + // b.ConfigureByConvention(); //auto configure for the base properties + // //... + //}); } } ```` -This simple `DbContext` class still needs some explanations: +This `DbContext` class needs some explanations: +* It defines `[ReplaceDbContext]` attributes for `IIdentityDbContext` and `ITenantManagementDbContext` those replaces Identity and Tenant Management module's `DbContext`s by your `DbContext` on runtime. This allows us to easily perform LINQ queries by joining your entities with the entities (over the repositories) coming from those modules. * It defines a `[ConnectionStringName]` attribute which tells ABP to always use the `Default` connection string for this `Dbcontext`. * It inherits from the `AbpDbContext` instead of the standard `DbContext` class. You can see the [EF Core integration](Entity-Framework-Core.md) document for more. For now, know that the `AbpDbContext` 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](Modules/Identity.md). 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. +* It declares `DbSet` properties for entities from the replaced `DbContext`s (by implementing the corresponding interfaces). These `DbSet` properties are not shown above (for the sake of brevity), but you can find in your application's code in a `region`. * The constructor takes a `DbContextOptions` 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 (it shares a table with the Identity module), 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. - -##### Sharing the Mapping Code + * It then calls some `builder.ConfigureXXX()` methods for the used modules. This makes possible to add database mappings for these modules to this `DbContext`, so it creates the database tables of the modules when we add a new EF Core database migration. + * You can configure the mappings for your own entities as commented in the example code. At this point, you can also change mappings for the modules you are using. -First problem is that: A module uses its own `DbContext` which needs to the database mappings. The `ApplicationDbContext` also needs to the same mapping in order to create the database tables for this module. We definitely **don't want to duplicate** the mapping code. +### Discussion of an Alternative Scenario: Every Module Manages Its Own Migration Path -The solution is to define an **extension method** (on the `ModelBuilder`) that can be called by both `DbContext` classes. So, all modules define such extension methods. +As mentioned before, in the `.EntityFrameworkCore` project, we merge all the database mappings of all the modules (plus your application's mappings) to create a unified migration path. -For example, the `builder.ConfigureBackgroundJobs()` method call configures the database tables for the [Background Jobs module](Modules/Background-Jobs.md). The definition of this extension method is something like that: +An alternative approach would be to allow each module to have its own migrations to maintain its database tables. While it seems more modular in the beginning, it has some drawbacks in practical: -````csharp -public static class BackgroundJobsDbContextModelCreatingExtensions -{ - public static void ConfigureBackgroundJobs( - this ModelBuilder builder, - Action optionsAction = null) - { - var options = new BackgroundJobsModelBuilderConfigurationOptions( - BackgroundJobsDbProperties.DbTablePrefix, - BackgroundJobsDbProperties.DbSchema - ); +* **EF Core migration system depends on the DBMS provider**. For example, if a module has created migrations for SQL Server, then you can not use this migration code for MySQL. It is not practical for a module to maintain migrations for all available DBMS providers. Leaving the migration to the application code (as explained in this document) allows you to **choose the DBMS in the application** code. If you can depend on a specific DBMS in your module, that's not an issue for you, however all pre-built ABP modules are DBMS agnostic. +* It would be harder to **customize/enhance** the mapping and the resulting migration code, in the final application. +* It would be harder to track and **apply changes** to database when you use multiple modules. - optionsAction?.Invoke(options); - - builder.Entity(b => - { - b.ToTable(options.TablePrefix + "BackgroundJobs", options.Schema); +## Using Multiple Databases - b.ConfigureCreationTime(); - b.ConfigureExtraProperties(); +The default startup template is organized to use a **single database** used by all the modules and by your application. However, the ABP Framework and all the pre-built modules are designed so that **they can use multiple databases**. Each module can use its own database or you can group modules into a few databases. - b.Property(x => x.JobName) - .IsRequired() - .HasMaxLength(BackgroundJobRecordConsts.MaxJobNameLength); - - //... - }); - } -} -```` - -This extension method also gets options to change the database table prefix and schema for this module, but it is not important here. +This section will explain how to move Audit Logging, Setting Management and Permission Management module tables to a **second database** while the remaining modules continue to use the main ("Default") database. -The final application calls the extension methods inside the `ApplicationDbContext` class, so it can decide which modules are included in the database maintained by this `ApplicationDbContext`. If you want to create a second database and move some module tables to the second database, then you need to have a second `ApplicationDbContext` class which only calls the extension methods of the related modules. This topic will be detailed in the next sections. +The resulting structure will be like the figure below: -The same `ConfigureBackgroundJobs` method is also called in the `DbContext` of the Background Jobs module: +![single-database-usage](images/multiple-database-usage.png) -````csharp -[ConnectionStringName(BackgroundJobsDbProperties.ConnectionStringName)] -public class BackgroundJobsDbContext - : AbpDbContext, IBackgroundJobsDbContext -{ - public DbSet BackgroundJobs { get; set; } +### Change the Connection Strings Section - public BackgroundJobsDbContext(DbContextOptions options) - : base(options) - { +First step is to change the connection string section inside all the `appsettings.json` files. Initially, it is like that: - } +````json +"ConnectionStrings": { + "Default": "Server=(LocalDb)\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True" +} +```` - protected override void OnModelCreating(ModelBuilder builder) - { - base.OnModelCreating(builder); +Change it as shown below: - //Reuse the same extension method! - builder.ConfigureBackgroundJobs(); - } +````json +"ConnectionStrings": { + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True", + "AbpPermissionManagement": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore_SecondDb;Trusted_Connection=True", + "AbpSettingManagement": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore_SecondDb;Trusted_Connection=True", + "AbpAuditLogging": "Server=(LocalDb)\MSSQLLocalDB;Database=BookStore_SecondDb;Trusted_Connection=True" } ```` -In this way, the mapping configuration of a module can be shared between `DbContext` classes. The code above is inside the related module NuGet package, so you don't care about it. - -##### Reusing a Table of a Module +Added **three more connection strings** for the related module to target the `BookStore_SecondDb` database (they are all the same). For example, `AbpPermissionManagement` is the connection string name used by the permission management module. -You may want to **reuse a table** of a depended module in your application. In this case, you have two options: +The `AbpPermissionManagement` is a constant [defined](https://github.com/abpframework/abp/blob/97eaa6ff5a044f503465455c86332e5a277b077a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDbProperties.cs#L11) by the permission management module. ABP Framework [connection string selection system](Connection-Strings.md) selects this connection string for the permission management module if you define. If you don't define, it fallbacks to the `Default` connection string. -1. You can **directly use the entity** defined by the module (you can still [extend the entity](Customizing-Application-Modules-Extending-Entities.md) in some level). -2. You can **create a new entity** mapping to the same database table. +### Create a Second DbContext -###### Use the Entity Defined by a Module +Defining the connection strings as explained above is enough **on runtime**. However, `BookStore_SecondDb` database doesn't exist yet. You need to create the database and the tables for the related modules. -Using an entity defined a module is pretty easy and standard. For example, Identity module defines the `IdentityUser` entity. You can inject the [repository](Repositories.md) for the `IdentityUser` and perform the standard repository operations for this entity. Example: +Just like the main database, we want to use the EF Core Code First migration system to create and maintain the second database. So, create a new `DbContext` class inside the `.EntityFrameworkCore` project: ````csharp -using System; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Repositories; -using Volo.Abp.Identity; - -namespace Acme.BookStore +using Microsoft.EntityFrameworkCore; +using Volo.Abp.AuditLogging.EntityFrameworkCore; +using Volo.Abp.Data; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.PermissionManagement.EntityFrameworkCore; +using Volo.Abp.SettingManagement.EntityFrameworkCore; + +namespace BookStore.EntityFrameworkCore { - public class MyService : ITransientDependency + [ConnectionStringName("AbpPermissionManagement")] + public class BookStoreSecondDbContext : + AbpDbContext { - private readonly IRepository _identityUserRepository; - - public MyService(IRepository identityUserRepository) + public BookStoreSecondDbContext( + DbContextOptions options) + : base(options) { - _identityUserRepository = identityUserRepository; } - public async Task DoItAsync() + protected override void OnModelCreating(ModelBuilder builder) { - //Get all users - var users = await _identityUserRepository.GetListAsync(); - } - } -} -```` + base.OnModelCreating(builder); -This example injects the `IRepository` (default repository) which defines the standard repository methods and implements the `IQueryable` interface. - -> In addition, Identity module defines the `IIdentityUserRepository` (custom repository) that can also be injected and used by your application. `IIdentityUserRepository` provides additional custom methods for the `IdentityUser` entity while it does not implement the `IQueryable` interface. - -###### Create a New Entity - -Working with an entity of a module is easy if you want to use the entity as is. However, you may want to define your own entity class and map to the same database table in the following cases; - -* You want to **add a new field** to the table and map it to a property in the entity. You can't use the module's entity since it doesn't have the related property. -* You want to **use a subset of the table fields**. You don't want to access to all properties of the entity and hide the unrelated properties (from a security perspective or just by design). -* You don't want to directly **depend on** a module entity class. - -In any case, the progress is same. Assume that you want to create an entity, named `AppRole`, mapped to the same table of the `IdentityRole` entity of the [Identity module](Modules/Identity.md). - -Here, we will show the implementation, then **will discuss the limitations** of this approach. - -First, create a new `AppRole` class in your `.Domain` project: - -````csharp -using System; -using Volo.Abp.Domain.Entities; -using Volo.Abp.MultiTenancy; - -namespace Acme.BookStore.Roles -{ - public class AppRole : AggregateRoot, IMultiTenant - { - // Properties shared with the IdentityRole class - - public Guid? TenantId { get; private set; } - public string Name { get; private set; } - - //Additional properties - - public string Title { get; set; } - - private AppRole() - { - + /* Include modules to your migration db context */ + builder.ConfigurePermissionManagement(); + builder.ConfigureSettingManagement(); + builder.ConfigureAuditLogging(); } } } ```` -* It's inherited from [the `AggregateRoot` class](Entities.md) and implements [the `IMultiTenant` interface](Multi-Tenancy.md) because the `IdentityRole` also does the same. -* You can add any properties defined by the `IdentityRole` entity. This examples add only the `TenantId` and `Name` properties since we only need them here. You can make the setters private (like in this example) to prevent changing Identity module's properties accidently. -* You can add custom (additional) properties. This example adds the `Title` property. -* The **constructor is private**, so it is not allowed to directly create a new `AppRole` entity. Creating a role is a responsibility of the Identity module. You can query roles, set/update your custom properties, but you should not create or delete a role in your code, as a best practice (while there is nothing restricts you). - -Now, it is time to define the EF Core mappings. Open the `DbContext` of your application (`BookStoreDbContext` in this sample) and add the following property: - -````csharp -public DbSet Roles { get; set; } -```` +> `[ConnectionStringName(...)]` attribute is important here and tells to the ABP Framework which connection string should be used for this `DbContext`. We've used `AbpPermissionManagement`, but all are the same. -Then configure the mapping inside the `OnModelCreating` method (after calling the `base.OnModelCreating(builder)`): +We need to register this `BookStoreSecondDbContext` class to the dependency injection system. Open the `BookStoreEntityFrameworkCoreModule` class in the `BookStore.EntityFrameworkCore` project and add the following line into the `ConfigureServices` method: ````csharp -protected override void OnModelCreating(ModelBuilder builder) -{ - base.OnModelCreating(builder); - - /* Configure the shared tables (with included modules) here */ - - //CONFIGURE THE AppRole ENTITY - builder.Entity(b => - { - b.ToTable("AbpRoles"); - b.ConfigureByConvention(); - b.Property(x => x.Title).HasMaxLength(128); - }); - - ... - - /* Configure your own tables/entities inside the ConfigureBookStore method */ - - builder.ConfigureBookStore(); -} +context.Services.AddAbpDbContext(); ```` -We added the following lines: +We should also create a **Design Time Db Factory** class, that is used by the EF Core tooling (by `Add-Migration` and `Update-Database` PCM commands for example): ````csharp -builder.Entity(b => -{ - b.ToTable("AbpRoles"); - b.ConfigureByConvention(); - b.Property(x => x.Title).HasMaxLength(128); -}); -```` +using System.IO; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; -* It maps to the same `AbpRoles` table shared with the `IdentityRole` entity. -* `ConfigureByConvention()` configures the standard/base properties (like `TenantId`) and recommended to always call it. - -You've configured the custom property for your `DbContext` that is used by your application on the runtime. We also need to configure the `MigrationsDbContext`. - -Instead of directly changing the `MigrationsDbContext`, we **should** use the entity extension system of the ABP Framework. Find the `YourProjectNameEfCoreEntityExtensionMappings` class in the `.EntityFrameworkCore` project of your solution (`BookStoreEfCoreEntityExtensionMappings` for this example) and change it as shown below: - -````csharp -public static class MyProjectNameEntityExtensions +namespace BookStore.EntityFrameworkCore { - private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); - - public static void Configure() + /* This class is needed for EF Core console commands + * (like Add-Migration and Update-Database commands) */ + public class BookStoreSecondDbContextFactory + : IDesignTimeDbContextFactory { - OneTimeRunner.Run(() => + public BookStoreSecondDbContext CreateDbContext(string[] args) { - ObjectExtensionManager.Instance - .MapEfCoreProperty( - "Title", - (entityBuilder, propertyBuilder) => - { - propertyBuilder.HasMaxLength(128); - } - ); - }); - } -} -```` - -> Instead of hard-coded "Title" string, we suggest to use `nameof(AppRole.Title)` or use a constant string. - -`ObjectExtensionManager` is used to add properties to existing entities. Since `ObjectExtensionManager.Instance` is a static instance (singleton), we should call it once. `OneTimeRunner` is a simple utility class defined by the ABP Framework. - -See the [EF Core integration documentation](Entity-Framework-Core.md) for more about the entity extension system. - -> We've repeated a similar database mapping code, like `HasMaxLength(128)`, in both classes. - -Now, you can add a new EF Core database migration using the standard `Add-Migration` command in the Package Manager Console (remember to select `.EntityFrameworkCore` as the Default Project in the PMC and make sure that the `.Web` project is still the startup project): - -![pmc-add-migration-role-title](images/pmc-add-migration-role-title.png) - -This command will create a new code first migration class as shown below: - -````csharp -public partial class Added_Title_To_Roles : Migration -{ - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "Title", - table: "AbpRoles", - maxLength: 128, - nullable: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "Title", - table: "AbpRoles"); - } -} -```` - -All done! Just run the `Update-Database` command in the PMC or run the `.DbMigrator` project in your solution to apply changes to database. - -Now, you can work with the `AppRole` entity just like any other entity of your application. An example [application service](Application-Services.md) that queries and updates roles: - -````csharp -public class AppRoleAppService : ApplicationService, IAppRoleAppService -{ - private readonly IRepository _appRoleRepository; - - public AppRoleAppService(IRepository appRoleRepository) - { - _appRoleRepository = appRoleRepository; - } + var configuration = BuildConfiguration(); + var builder = new DbContextOptionsBuilder() + .UseSqlServer(configuration.GetConnectionString("AbpPermissionManagement")); + return new BookStoreSecondDbContext(builder.Options); + } - public async Task> GetListAsync() - { - var roles = await _appRoleRepository.GetListAsync(); - - return roles - .Select(r => new AppRoleDto - { - Id = r.Id, - Name = r.Name, - Title = r.Title - }) - .ToList(); - } + private static IConfigurationRoot BuildConfiguration() + { + var builder = new ConfigurationBuilder() + .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../BookStore.DbMigrator/")) + .AddJsonFile("appsettings.json", optional: false); - public async Task UpdateTitleAsync(Guid id, string title) - { - var role = await _appRoleRepository.GetAsync(id); - - role.Title = title; - - await _appRoleRepository.UpdateAsync(role); + return builder.Build(); + } } } ```` -There are some **limitations** of creating a new entity and mapping it to a table of a depended module: - -* Your **custom properties must be nullable**. For example, `AppRole.Title` was nullable here. Otherwise, Identity module throws exception because it doesn't know and can not fill the Title when it inserts a new role to the database. -* As a good practice, you should not update the **properties defined by the module**, especially if it requires a business logic. You typically want to manage your own properties. - -##### Alternative Approaches - -Instead of creating a new entity class to add a custom property, you can use the following approaches. - -###### Using the ExtraProperties - -All entities derived from the `AggregateRoot ` class can store name-value pairs in their `ExtraProperties` property (because they implement the `IHasExtraProperties` interface), which is a `Dictionary` serialized to JSON in the database table. So, you can add values to this dictionary and query again without changing the entity. - -For example, you can store query the title Property inside an `IdentityRole` instead of creating a new entity. Example: +Now, you can open the Package Manager Console, select the `.EntityFrameworkCore` project as the default project (make sure the `.Web` project is still the startup project) and run the following command: -````csharp -public class IdentityRoleExtendingService : ITransientDependency -{ - private readonly IIdentityRoleRepository _identityRoleRepository; - - public IdentityRoleExtendingService(IIdentityRoleRepository identityRoleRepository) - { - _identityRoleRepository = identityRoleRepository; - } - - public async Task GetTitleAsync(Guid id) - { - var role = await _identityRoleRepository.GetAsync(id); - return role.GetProperty("Title"); - } - - public async Task SetTitleAsync(Guid id, string newTitle) - { - var role = await _identityRoleRepository.GetAsync(id); - role.SetProperty("Title", newTitle); - await _identityRoleRepository.UpdateAsync(role); - } -} +````bash +Add-Migration "Initial" -OutputDir "SecondDbMigrations" -Context BookStoreSecondDbContext ```` -* `GetProperty` and `SetProperty` methods are shortcuts to get and set a value in the `role.ExtraProperties` dictionary and they are the recommended way to work with the extra properties. - -In this way, you can easily attach any type of value to an entity of a depended module. However, there are some drawbacks of this usage: - -* All the extra properties are stored as **a single JSON object** in the database. They are not stored as new table fields, as you may expect. Creating database table indexes and using SQL queries against these properties will be harder compared to simple table fields. -* Property names are strings, so they are **not type safe**. It is recommended to define constants for these kind of properties to prevent typo errors. - -###### Using the Entity Extensions System - -Entity extension system solves the main problem of the extra properties: It can store an extra property in a **standard table field** in the database. - -All you need to do is to use the `ObjectExtensionManager` to define the extra property as explained above, in the `AppRole` example. Then you can continue to use the same `GetProperty` and `SetProperty` methods defined above to get/set the related property on the entity, but this time stored as a separate field in the database. - -See the [entity extension system](Customizing-Application-Modules-Extending-Entities.md) for details. - -###### Creating a New Table - -Instead of creating a new entity and mapping to the same table, you can also create **your own table** to store your properties. You typically duplicate some values of the original entity. For example, you can add `Name` field to your own table which is a duplication of the `Name` field in the original table. - -In this case, you don't deal with migration problems, however you need to deal with the problems of data duplication. When the duplicated value changes, you should reflect the same change in your table. You can use local or distributed [event bus](Event-Bus.md) to subscribe to the change events for the original entity. This is the recommended way of depending on a microservice's data from another microservice, especially if they have separate physical databases (you can search on the web on data sharing on a microservice design, it is a wide topic to cover here). - -> See the "[extending entities](Customizing-Application-Modules-Extending-Entities.md)" guide for more details on extending entities, including data duplication and synchronization tips. +This will add a `SecondDbMigrations` folder in the `.EntityFrameworkCore` project and a migration class inside it. `OutputDir` and `Context` parameters are required since we currently have two `DbContext` class and two migrations folder in the same project. -#### Discussion of an Alternative Scenario: Every Module Manages Its Own Migration Path +You can now run the following command to create the database and the tables inside it: -As mentioned before, `.EntityFrameworkCore` merges all the database mappings of all the modules (plus your application's mappings) to create a unified migration path. - -An alternative approach would be to allow each module to have its own migrations to maintain its database tables. While it seems more module in the beginning, it has some important drawbacks: - -* **EF Core migration system depends on the DBMS provider**. For example, if a module has created migrations for SQL Server, then you can not use this migration code for MySQL. It is not practical for a module to maintain migrations for all available DBMS providers. Leaving the migration to the application code (as explained in this document) allows you to **choose the DBMS in the application** code. -* It would be harder or impossible to **share a table** between modules or **re-use a table** of a module in your application. Because EF Core migration system can not handle it and will throw exceptions like "Table XXX is already exists in the database". -* It would be harder to **customize/enhance** the mapping and the resulting migration code. -* It would be harder to track and **apply changes** to database when you use multiple modules. - -## Using Multiple Databases - -The default startup template is organized to use a single database used by all the modules and by your application. However, the ABP Framework and all the pre-built modules are designed so that **they can use multiple databases**. Each module can use its own database or you can group modules into a few databases. - -This section will explain how to move Audit Logging, Setting Management and Permission Management module tables to a **second database** while the remaining modules continue to use the main ("Default") database. - -The resulting structure will be like the figure below: - -![single-database-usage](images/multiple-database-usage.png) - -### Change the Connection Strings Section - -First step is to change the connection string section inside all the `appsettings.json` files. Initially, it is like that: - -````json -"ConnectionStrings": { - "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True" -} +````bash +Update-Database -Context BookStoreSecondDbContext ```` -Change it as shown below: - -````json -"ConnectionStrings": { - "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True", - "AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True", - "AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True", - "AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True" -} -```` - -Added **three more connection strings** for the related module to target the `BookStore_SecondDb` database (they are all same). For example, `AbpPermissionManagement` is the connection string for the permission management module. - -The `AbpPermissionManagement` is a constant [defined](https://github.com/abpframework/abp/blob/97eaa6ff5a044f503465455c86332e5a277b077a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDbProperties.cs#L11) by the permission management module. ABP Framework [connection string selection system](Connection-Strings.md) selects this connection string for the permission management module if you define. If you don't define, it fallbacks to the `Default` connection string. +A new database, named `BookStore_SecondDb` should be created. ### Remove Modules from the Main Database -We've **created a second database** contains tables for the Audit Logging, Permission Management and Setting Management modules. So, we should **delete these tables from the main database**. It is pretty easy. +We've **created a second database** that contains tables for the Audit Logging, Permission Management and Setting Management modules. So, we should **delete these tables from the main database**. It is pretty easy. -First, remove the following lines from the `MigrationsDbContext` class (`BookStoreMigrationsDbContext` for this example): +First, remove the following lines from the `BookStoreDbContext` class: ````csharp builder.ConfigurePermissionManagement(); @@ -573,7 +305,7 @@ builder.ConfigureAuditLogging(); Open the Package Manager Console, select the `.EntityFrameworkCore` as the Default project (make sure that the `.Web` project is still the startup project) and run the following command: ```` -Add-Migration "Removed_Audit_Setting_Permission_Modules" +Add-Migration "Removed_Audit_Setting_Permission_Modules" -Context BookStoreDbContext ```` This command will create a new migration class as shown below: @@ -611,88 +343,148 @@ Be careful in this step: * If you have a **live system**, then you should care about the **data loss**. You need to move the table contents to the second database before deleting the tables. * If you **haven't started** your project yet, you can consider to **remove all the migrations** and re-create the initial one to have a cleaner migration history. -Run the `Update-Database` command to delete the tables from your main database. +Run the following command to delete the tables from your main database: + +````bash +Update-Database -Context BookStoreDbContext +```` Notice that you've also **deleted some initial seed data** (for example, permission grants for the admin role) if you haven't copied it to the new database. If you run the application, you may not login anymore. The solution is simple: **Re-run the `.DbMigrator` console application** in your solution, it will seed the new database. ### Automate the Second Database Schema Migration -`.DbMigrator` console application can run the database seed code across multiple databases, without any additional configuration. However, it can not run the EF Core Code First Migrations inside the second database migration project. Now, you will see how to configure the console migration application to handle both databases. - -#### Implementing the IBookStoreDbSchemaMigrator +`.DbMigrator` console application can run the database seed code across multiple databases, without any additional configuration. However, it can not apply the EF Core Code First Migrations for the database of the `BookStoreSecondDbContext`. Now, you will see how to configure the console migration application to handle both databases. `EntityFrameworkCoreBookStoreDbSchemaMigrator` class inside the `Acme.BookStore.EntityFrameworkCore` project is responsible to migrate the database schema for the `BookStoreMigrationsDbContext`. It should be like that: ````csharp -[Dependency(ReplaceServices = true)] -public class EntityFrameworkCoreBookStoreDbSchemaMigrator - : IBookStoreDbSchemaMigrator, ITransientDependency -{ - private readonly IServiceProvider _serviceProvider; +using System; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using BookStore.Data; +using Volo.Abp.DependencyInjection; - public EntityFrameworkCoreBookStoreDbSchemaMigrator( - IServiceProvider serviceProvider) +namespace BookStore.EntityFrameworkCore +{ + public class EntityFrameworkCoreBookStoreDbSchemaMigrator + : IBookStoreDbSchemaMigrator, ITransientDependency { - _serviceProvider = serviceProvider; - } + private readonly IServiceProvider _serviceProvider; - public async Task MigrateAsync() - { - /* We are intentionally resolving the BookStoreMigrationsDbContext - * from IServiceProvider (instead of directly injecting it) - * to properly get the connection string of the current tenant in the - * current scope. - */ - - await _serviceProvider - .GetRequiredService() - .Database - .MigrateAsync(); + public EntityFrameworkCoreBookStoreDbSchemaMigrator( + IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public async Task MigrateAsync() + { + /* We intentionally resolving the BookStoreDbContext + * from IServiceProvider (instead of directly injecting it) + * to properly get the connection string of the current tenant in the + * current scope. + */ + + await _serviceProvider + .GetRequiredService() + .Database + .MigrateAsync(); + } } } ```` -It implements the `IBookStoreDbSchemaMigrator` and **replaces existing services** (see the first line). +Add the following code inside the `MigrateAsync` method: -Remove the `[Dependency(ReplaceServices = true)]` line, because we will have two implementations of this interface and we want to use both. We don't want to replace one of them. +````csharp +await _serviceProvider + .GetRequiredService() + .Database + .MigrateAsync(); +```` -Create a copy of this class inside the new migration project (`Acme.BookStore.EntityFrameworkCore.ForSecondDb`), but use the `BookStoreSecondMigrationsDbContext`. Example implementation: +So, the `MigrateAsync` method should look like the following: ````csharp -public class EntityFrameworkCoreSecondBookStoreDbSchemaMigrator - : IBookStoreDbSchemaMigrator, ITransientDependency +public async Task MigrateAsync() { - private readonly IServiceProvider _serviceProvider; + /* We intentionally resolving the BookStoreDbContext + * from IServiceProvider (instead of directly injecting it) + * to properly get the connection string of the current tenant in the + * current scope. + */ + + await _serviceProvider + .GetRequiredService() + .Database + .MigrateAsync(); + + await _serviceProvider + .GetRequiredService() + .Database + .MigrateAsync(); +} +```` - public EntityFrameworkCoreSecondBookStoreDbSchemaMigrator( - IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } +That's all. You can now run the `.DbMigrator` application to migrate & seed the databases. To test, you can delete both databases and run the `.DbMigrator` application again to see if it creates both of the databases. + +### Fixing the Tests + +Creating a new DbContext will break the integration tests. It is easy to fix. Open the `BookStoreEntityFrameworkCoreTestModule` class in the `BookStore.EntityFrameworkCore.Tests` project, find the `CreateDatabaseAndGetConnection` method. It should be like that: + +````csharp +private static SqliteConnection CreateDatabaseAndGetConnection() +{ + var connection = new SqliteConnection("Data Source=:memory:"); + connection.Open(); + + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; - public async Task MigrateAsync() + using (var context = new BookStoreDbContext(options)) { - /* We are intentionally resolving the BookStoreSecondMigrationsDbContext - * from IServiceProvider (instead of directly injecting it) - * to properly get the connection string of the current tenant in the - * current scope. - */ - - await _serviceProvider - .GetRequiredService() - .Database - .MigrateAsync(); + context.GetService().CreateTables(); } + + return connection; } ```` -> Name of this class is important for [dependency injection](Dependency-Injection.md). It should end with `BookStoreDbSchemaMigrator` to be injectable by `IBookStoreDbSchemaMigrator` reference. +Change it as the following: + +````csharp +private static SqliteConnection CreateDatabaseAndGetConnection() +{ + var connection = new SqliteConnection("Data Source=:memory:"); + connection.Open(); + + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + using (var context = new BookStoreDbContext(options)) + { + context.GetService().CreateTables(); + } + + // Add the following code -------------- + var optionsForSecondDb = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; -We, now, have two implementations of the `IBookStoreDbSchemaMigrator` interface, each one responsible to migrate the related database schema. + using (var context = new BookStoreSecondDbContext(optionsForSecondDb)) + { + context.GetService().CreateTables(); + } + //-------------------------------------- -#### Run the Database Migrator! + return connection; +} +```` -You can run the `.DbMigrator` application to migrate & seed the databases. To test, you can delete both databases and run the `.DbMigrator` application again to see if it creates both of the databases. +Integration tests now will work. I've used the same database in the tests to keep it simple. ## Separating Host & Tenant Database Schemas @@ -700,7 +492,7 @@ In a multi-tenant solution, you may want to separate your database schemas, so h Some pre-built ABP modules are related only with the host side, like the [Tenant Management](Modules/Tenant-Management.md) module. So, in the tenant `DbContext` class you don't call `modelBuilder.ConfigureTenantManagement()` and that's all. -However, some modules, like the [Identity](Modules/Identity.md) module, is both used in host and tenant sides. It stores tenant users in the tenant database and host users in the host database. However, it stores some entities, like `IdentityClaimType`, only in the host side. In this case, you don't want to add these tables in the tenant database, even if they are not used and will always be empty. +Some modules, like the [Identity](Modules/Identity.md) module, is both used in host and tenant sides. It stores tenant users in the tenant database and host users in the host database. However, it stores some entities, like `IdentityClaimType`, only in the host side. In this case, you don't want to add these tables in the tenant database, even if they are not used and will always be empty for tenants. ABP provides a simple way to set the multi-tenancy side for a `DbContext`, so the modules can check it and decide to map tables to the database, or not. @@ -712,6 +504,7 @@ public class MyTenantDbContext : AbpDbContext modelBuilder.SetMultiTenancySide(MultiTenancySides.Tenant); base.OnModelCreating(modelBuilder); + modelBuilder.ConfigureIdentity(); modelBuilder.ConfigureFeatureManagement(); modelBuilder.ConfigureAuditLogging(); @@ -761,4 +554,4 @@ This document explains how to split your databases and manage your database migr ## Source Code -You can find the source code of the example project referenced by this document [here](https://github.com/abpframework/abp-samples/tree/master/EfCoreMigrationDemo). However, you need to read and understand this document in order to understand the example project's source code. \ No newline at end of file +You can find the source code of the example project referenced by this document [here](https://github.com/abpframework/abp-samples/tree/master/EfCoreMigrationDemo). You can also find the changes explained in this document as a [single commit](https://github.com/abpframework/abp-samples/pull/95/commits/c2ffd76175e0a6fdfcf6477bbaea23dc2793fedd). \ No newline at end of file From 538a17b285b15cb72c35e64b34adbc337c79b9e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87otur?= Date: Fri, 9 Jul 2021 10:15:01 +0300 Subject: [PATCH 13/13] update missing parts --- docs/en/Entity-Framework-Core-MySQL.md | 2 +- docs/en/Entity-Framework-Core-Oracle-Devart.md | 10 +++++----- docs/en/Entity-Framework-Core-Oracle-Official.md | 8 ++++---- docs/en/Entity-Framework-Core-PostgreSQL.md | 2 +- docs/en/Entity-Framework-Core-SQLite.md | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/en/Entity-Framework-Core-MySQL.md b/docs/en/Entity-Framework-Core-MySQL.md index 53469e95d9..92a9cfb36e 100644 --- a/docs/en/Entity-Framework-Core-MySQL.md +++ b/docs/en/Entity-Framework-Core-MySQL.md @@ -15,7 +15,7 @@ Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFra Find `UseSqlServer()` calls in your solution. Check the following files: * *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. Replace `UseSqlServer()` with `UseMySQL()`. -* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project. Replace `UseSqlServer()` with `UseMySql()`. Then add a new parameter (`ServerVersion`) to `UseMySql()` method. Example: `.UseMySql(configuration.GetConnectionString("Default"), ServerVersion.FromString("8.0.21-mysql"))`. See [this issue](https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/pull/1233) for more information about `ServerVersion`) +* *YourProjectName*DbContextFactory.cs inside the `.EntityFrameworkCore` project. Replace `UseSqlServer()` with `UseMySql()`. Then add a new parameter (`ServerVersion`) to `UseMySql()` method. Example: `.UseMySql(configuration.GetConnectionString("Default"), ServerVersion.FromString("8.0.21-mysql"))`. See [this issue](https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/pull/1233) for more information about `ServerVersion`) > Depending on your solution structure, you may find more code files need to be changed. diff --git a/docs/en/Entity-Framework-Core-Oracle-Devart.md b/docs/en/Entity-Framework-Core-Oracle-Devart.md index 96f02714ab..95e05db427 100644 --- a/docs/en/Entity-Framework-Core-Oracle-Devart.md +++ b/docs/en/Entity-Framework-Core-Oracle-Devart.md @@ -19,20 +19,20 @@ Also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Ab Find `UseSqlServer()` calls in your solution, replace with `UseOracle()`. Check the following files: * *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. -* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project. +* *YourProjectName*DbContextFactory.cs inside the `.EntityFrameworkCore` project. -In the `CreateDbContext()` method of the *YourProjectName*MigrationsDbContextFactory.cs, replace the following code block +In the `CreateDbContext()` method of the *YourProjectName*DbContextFactory.cs, replace the following code block ```csharp -var builder = new DbContextOptionsBuilder() +var builder = new DbContextOptionsBuilder() .UseSqlServer(configuration.GetConnectionString("Default")); ``` with this one ```csharp -var builder = (DbContextOptionsBuilder) - new DbContextOptionsBuilder().UseOracle +var builder = (DbContextOptionsBuilder) + new DbContextOptionsBuilder().UseOracle ( configuration.GetConnectionString("Default") ); diff --git a/docs/en/Entity-Framework-Core-Oracle-Official.md b/docs/en/Entity-Framework-Core-Oracle-Official.md index aab71c9e59..d983dc5e41 100644 --- a/docs/en/Entity-Framework-Core-Oracle-Official.md +++ b/docs/en/Entity-Framework-Core-Oracle-Official.md @@ -17,19 +17,19 @@ Also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Ab Find `UseSqlServer()` calls in your solution, replace with `UseOracle()`. Check the following files: * *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. -* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project. +* *YourProjectName*DbContextFactory.cs inside the `.EntityFrameworkCore` project. -In the `CreateDbContext()` method of the *YourProjectName*MigrationsDbContextFactory.cs, replace the following code block +In the `CreateDbContext()` method of the *YourProjectName*DbContextFactory.cs, replace the following code block ```csharp -var builder = new DbContextOptionsBuilder() +var builder = new DbContextOptionsBuilder() .UseSqlServer(configuration.GetConnectionString("Default")); ``` with this one (just changes `UseSqlServer(...)` to `UseOracle(...)`) ```csharp -var builder = new DbContextOptionsBuilder() +var builder = new DbContextOptionsBuilder() .UseOracle(configuration.GetConnectionString("Default")); ``` diff --git a/docs/en/Entity-Framework-Core-PostgreSQL.md b/docs/en/Entity-Framework-Core-PostgreSQL.md index a8dbdc7b67..f6a0c26806 100644 --- a/docs/en/Entity-Framework-Core-PostgreSQL.md +++ b/docs/en/Entity-Framework-Core-PostgreSQL.md @@ -15,7 +15,7 @@ Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFra Find `UseSqlServer()` call in *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project and replace with `UseNpgsql()`. -Find `UseSqlServer()` call in *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project and replace with `UseNpgsql()`. +Find `UseSqlServer()` call in *YourProjectName*DbContextFactory.cs inside the `.EntityFrameworkCore` project and replace with `UseNpgsql()`. > Depending on your solution structure, you may find more `UseSqlServer()` calls that needs to be changed. diff --git a/docs/en/Entity-Framework-Core-SQLite.md b/docs/en/Entity-Framework-Core-SQLite.md index bcd6c6d927..81d4b72de2 100644 --- a/docs/en/Entity-Framework-Core-SQLite.md +++ b/docs/en/Entity-Framework-Core-SQLite.md @@ -15,7 +15,7 @@ Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFra Find `UseSqlServer()` calls in your solution, replace with `UseSqlite()`. Check the following files: * *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. -* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore` project. +* *YourProjectName*DbContextFactory.cs inside the `.EntityFrameworkCore` project. > Depending on your solution structure, you may find more code files need to be changed.