From b671ab9c6018b61d093631d9043b555dab3f0da0 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 5 Jun 2020 01:22:28 +0200 Subject: [PATCH 1/5] Improvements to migration docs --- .../managing-schemas/migrations/applying.md | 183 +++++++++++ .../core/managing-schemas/migrations/index.md | 294 ++++++------------ .../managing-schemas/migrations/managing.md | 201 ++++++++++++ entity-framework/toc.yml | 4 + 4 files changed, 480 insertions(+), 202 deletions(-) create mode 100644 entity-framework/core/managing-schemas/migrations/applying.md create mode 100644 entity-framework/core/managing-schemas/migrations/managing.md diff --git a/entity-framework/core/managing-schemas/migrations/applying.md b/entity-framework/core/managing-schemas/migrations/applying.md new file mode 100644 index 0000000000..fbb2ebbe61 --- /dev/null +++ b/entity-framework/core/managing-schemas/migrations/applying.md @@ -0,0 +1,183 @@ +--- +title: Applying Migrations - EF Core +author: bricelam +ms.author: bricelam +ms.date: 05/06/2020 +uid: core/managing-schemas/migrations/applying +--- +# Applying Migrations + +Once your migrations have been added, they need to be deployed and applied to your databases. There are various strategies for doing this, with some being more appropriate for production environments, and others for the development lifecycle. + +> [!NOTE] +> Whatever your deployment strategy, always inspect the generated migrations and test them applying to a production database. A migration may drop a column when the intent was to rename it, or may fail for various when applied to a database. + +## SQL scripts + +The recommended way to deploy migrations to a production database is by generating SQL scripts. The advantages of this strategy include the following: + +* SQL scripts can be reviewed for accuracy; this is important since applying schema changes to production databases is a potentially dangerous operation that could involve data loss. +* In some cases, the scripts can be tuned to fit the specific needs of a production database. +* SQL scripts can be used in conjunction with a deployment technology. +* SQL scripts can be provided to a DBA, and can be managed and archived separately. + +### [.NET Core CLI](#tab/dotnet-core-cli) + +#### Basic Usage + +The following generates a SQL script from a blank database to the latest migration: + +```dotnetcli +dotnet ef migrations script +``` + +#### With From (to implied) + +The following generates a SQL script from the given migration to the latest migration. + +```dotnetcli +dotnet ef migrations script AddNewTables +``` + +#### With From and To + +The following generates a SQL script from the `from` migration to the specified `to` migration. + +```dotnetcli +dotnet ef migrations script AddNewTables AddAuditTable +``` + +You can use a `from` that is newer than the `to` in order to generate a rollback script. *Please take note of potential data loss scenarios.* + +### [Visual Studio](#tab/vs) + +The following generates a SQL script from a blank database to the latest migration: + +#### Basic Usage + +``` powershell +Script-Migration +``` + +#### With From (to implied) + +The following generates a SQL script from this migration to the latest migration. + +```powershell +Script-Migration AddNewTables +``` + +#### With From and To + +The following generates a SQL script from the `from` migration to the specified `to` migration. + +```powershell +Script-Migration AddNewTables AddAuditTable +``` +You can use a `from` that is newer than the `to` in order to generate a rollback script. *Please take note of potential data loss scenarios.* + +*** + +There are several options to this command. + +The **from** migration should be the last migration applied to the database before running the script. If no migrations have been applied, specify `0` (this is the default). + +The **to** migration is the last migration that will be applied to the database after running the script. This defaults to the last migration in your project. + +## Idempotent SQL scripts + +The SQL scripts generated above can only be applied to change your schema from one migration to another; it is your responsibility to apply the script appropriately, and only to database in the correct migration state. EF Core also supports generating **idempotent** scripts, which internally check which migrations have already been applied, and only apply missing ones. This is useful if you don't exactly know what the last migration applied to the database was, or if you are deploying to multiple databases that may each be at a different migration. + +The following generates idempotent migrations: + +#### [.NET Core CLI](#tab/dotnet-core-cli) + +```dotnetcli +dotnet ef migrations add AddNewTables --idempotent +``` + +#### [Visual Studio](#tab/vs) + +``` powershell +Add-Migration AddNewTables -Idempotent +``` + +> [!WARNING] +> Idempotent scripts have some known limitations and will not work in all scenarios. + +*** + +## Command-line tools + +The EF command-line tools can be used to apply migrations to a database. While productive for local development and testing of migrations, this approach is inappropriate for management of production databases: + +* The SQL commands are applied directly by the tool, without giving the developer a change to inspect or modify them. This can be dangerous in a production environment. +* The .NET SDK and the EF tool must be installed on production servers. + +### [.NET Core CLI](#tab/dotnet-core-cli) + +The following updates your database to the latest migration: + +```dotnetcli +dotnet ef database update +``` + +The following updates your database to a given migration: + +```dotnetcli +dotnet ef database update AddNewTables +``` + +### [Visual Studio](#tab/vs) + +The following updates your database to the latest migration: + +``` powershell +Update-Database +``` + +The following updates your database to a given migration: + +``` powershell +Update-Database AddNewTables +``` + +*** + +Note that this can be used to roll back to an earlier migration as well. *Please take note of potential data loss scenarios.* + +For more information on applying migrations via the command-line tools, see the [EF Core tools reference](xref:core/miscellaneous/cli/index). + +## Apply migrations at runtime + +It's possible for the application itself to apply migrations programmatically, typically during startup. While productive for local development and testing of migrations, this approach is inappropriate for management of production databases: + +* If multiple instances of your application are running, both applications could attempt to apply the migration concurrently and fail (or worse, cause data corruption). +* Similarly, if an application is accessing the database while another application migrates it, this can cause severe issues. +* This requires the application to have elevated access to modify the database schema. It's generally good practice to limit the application's database permissions in production. +* It's important to be able to roll back an applied migration in case of an issue. The other strategies provide this easily and out of the box. +* The SQL commands are applied directly by the program, without giving the developer a change to inspect or modify them. This can be dangerous in a production environment. + +To apply migrations programmatically, call `myDbContext.Database.Migrate()`. For example, a typical ASP.NET application can do the following: + +```c# +public static void Main(string[] args) +{ + var host = CreateHostBuilder(args).Build(); + + using (var scope = host.Services.CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + db.Database.Migrate(); + } + + host.Run(); +} +``` + +Note that `Migrate()` builds on top of the `IMigrator` service, which can be used for more advanced scenarios. Use `myDbContext.GetInfrastructure().GetService()` to access it. + +> [!WARNING] +> +> * Carefully consider before using this approach in production. Experience has shown that the simplicity of this deployment strategy is outweighed by the problem it brings. Consider using SQL scripts instead. +> * Don't call `EnsureCreated()` before `Migrate()`. `EnsureCreated()` bypasses Migrations to create the schema, which causes `Migrate()` to fail. diff --git a/entity-framework/core/managing-schemas/migrations/index.md b/entity-framework/core/managing-schemas/migrations/index.md index 8ee0360ab3..002cb98dab 100644 --- a/entity-framework/core/managing-schemas/migrations/index.md +++ b/entity-framework/core/managing-schemas/migrations/index.md @@ -1,294 +1,184 @@ --- -title: Migrations - EF Core +title: Migrations Overview - EF Core author: bricelam ms.author: bricelam -ms.date: 10/05/2018 +ms.date: 05/06/2020 uid: core/managing-schemas/migrations/index --- -# Migrations +# Migrations Overview -A data model changes during development and gets out of sync with the database. You can drop the database and let EF create a new one that matches the model, but this procedure results in the loss of data. The migrations feature in EF Core provides a way to incrementally update the database schema to keep it in sync with the application's data model while preserving existing data in the database. +In real life projects, data models change as features get implemented: new entities or properties are added and removed, and databases schema needs to be changed accordingly to be kept in sync with the application. The migrations feature in EF Core provides a way to incrementally update the database schema to keep it in sync with the application's data model while preserving existing data in the database. -Migrations includes command-line tools and APIs that help with the following tasks: +At a high level, migrations functions in the following way: -* [Create a migration](#create-a-migration). Generate code that can update the database to sync it with a set of model changes. -* [Update the database](#update-the-database). Apply pending migrations to update the database schema. -* [Customize migration code](#customize-migration-code). Sometimes the generated code needs to be modified or supplemented. -* [Remove a migration](#remove-a-migration). Delete the generated code. -* [Revert a migration](#revert-a-migration). Undo the database changes. -* [Generate SQL scripts](#generate-sql-scripts). You might need a script to update a production database or to troubleshoot migration code. -* [Apply migrations at runtime](#apply-migrations-at-runtime). When design-time updates and running scripts aren't the best options, call the `Migrate()` method. +* When a data model change is introduced, the developer uses EF Core tools to add a corresponding migration describing the updates necessary to keep the database schema in sync. EF Core compares the current model against a snapshot of the old model to find out the differences, and generates migration source files; the files are kept in your project's source control like any other source file. +* Once a new migration has been generated, it can be deployed to a database in various ways. EF Core uses a migrations history table in the database which records all migrations which have already been applied; this allows EF Core to know which state your database is in. -> [!TIP] -> If the `DbContext` is in a different assembly than the startup project, you can explicitly specify the target and startup projects in either the [Package Manager Console tools](xref:core/miscellaneous/cli/powershell#target-and-startup-project) or the [.NET Core CLI tools](xref:core/miscellaneous/cli/dotnet#target-project-and-startup-project). +## Tutorial -## Install the tools +Let's assume you've just completed your first EF Core application, which contains the following simple model: -Install the [command-line tools](xref:core/miscellaneous/cli/index): - -* For Visual Studio, we recommend the [Package Manager Console tools](xref:core/miscellaneous/cli/powershell). -* For other development environments, choose the [.NET Core CLI tools](xref:core/miscellaneous/cli/dotnet). - -## Create a migration - -After you've [defined your initial model](xref:core/modeling/index), it's time to create the database. To add an initial migration, run the following command. - -### [.NET Core CLI](#tab/dotnet-core-cli) - -```dotnetcli -dotnet ef migrations add InitialCreate -``` - -### [Visual Studio](#tab/vs) - -``` powershell -Add-Migration InitialCreate +```c# +public class Blog +{ + public int Id { get; set; } + public string Name { get; set; } +} ``` -*** - -Three files are added to your project under the **Migrations** directory: +During development, you may have used the [Create and Drop APIs](xref:core/managing-schemas/ensure-created) to iterate quickly; but now that your application is going to production, you need a way to evolve the schema without dropping the entire database. -* **XXXXXXXXXXXXXX_InitialCreate.cs**--The main migrations file. Contains the operations necessary to apply the migration (in `Up()`) and to revert it (in `Down()`). -* **XXXXXXXXXXXXXX_InitialCreate.Designer.cs**--The migrations metadata file. Contains information used by EF. -* **MyContextModelSnapshot.cs**--A snapshot of your current model. Used to determine what changed when adding the next migration. +### Install the tools -The timestamp in the filename helps keep them ordered chronologically so you can see the progression of changes. +First, you'll have to install the [EF Core command-line tools](xref:core/miscellaneous/cli/index): -### Namespaces +* We generally recommend using the [.NET Core CLI tools](xref:core/miscellaneous/cli/dotnet), which work on all platforms. +* If you're more comfortable working inside Visual Studio or have experience with EF6 migrations, you can also use the [Package Manager Console tools](xref:core/miscellaneous/cli/powershell). -You are free to move Migrations files and change their namespace manually. New migrations are created as siblings of the last migration. +### Create your first migration -Alternatively you can use `-Namespace` (Package Manager Console) or `--namespace` (.NET Core CLI) to specify the namespace at generation time. +You're now ready to add your first migration! Instruct EF Core to create a migrations named **InitialCreate**: -### [.NET Core CLI](#tab/dotnet-core-cli) +#### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli -dotnet ef migrations add InitialCreate --namespace Your.Namespace +dotnet ef migrations add InitialCreate ``` -### [Visual Studio](#tab/vs) +#### [Visual Studio](#tab/vs) ``` powershell -Add-Migration InitialCreate -Namespace Your.Namespace +Add-Migration InitialCreate ``` *** -## Update the database +EF Core will create a directory called **Migrations**, and generated some files. In general, it's a good idea to inspect what exactly EF Core generated - and possibly amend it - but we'll skip over that for now. -Next, apply the migration to the database to create the schema. +### Create a migration SQL script -### [.NET Core CLI](#tab/dotnet-core-cli) +You now want to create your first production database and apply your migration there. In production scenarios, you typically need to create the database yourself, e.g. by using a cloud service user interface, or asking your DBA. Once an empty database is available, you can generate an *SQL script* from the migration we've just created: -```dotnetcli -dotnet ef database update -``` - -### [Visual Studio](#tab/vs) - -``` powershell -Update-Database -``` - -*** - -## Customize migration code - -After making changes to your EF Core model, the database schema might be out of sync. To bring it up to date, add another migration. The migration name can be used like a commit message in a version control system. For example, you might choose a name like *AddProductReviews* if the change is a new entity class for reviews. - -### [.NET Core CLI](#tab/dotnet-core-cli) +#### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli -dotnet ef migrations add AddProductReviews +dotnet ef migrations script -o InitialCreate.sql ``` - -### [Visual Studio](#tab/vs) +#### [Visual Studio](#tab/vs) ``` powershell -Add-Migration AddProductReviews +Script-Migration -Output InitialCreate.sql ``` *** -Once the migration is scaffolded (code generated for it), review the code for accuracy and add, remove or modify any operations required to apply it correctly. - -For example, a migration might contain the following operations: - -``` csharp -migrationBuilder.DropColumn( - name: "FirstName", - table: "Customer"); - -migrationBuilder.DropColumn( - name: "LastName", - table: "Customer"); +You now have an **InitialCreate.sql** script which can be executed against your empty database to create the schema corresponding to your model. If you're using SQL Server, the script should resemble the following: -migrationBuilder.AddColumn( - name: "Name", - table: "Customer", - nullable: true); -``` +```sql +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; -While these operations make the database schema compatible, they don't preserve the existing customer names. To make it better, rewrite it as follows. +GO -``` csharp -migrationBuilder.AddColumn( - name: "Name", - table: "Customer", - nullable: true); +CREATE TABLE [Blogs] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(max) NULL, + CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id]) +); -migrationBuilder.Sql( -@" - UPDATE Customer - SET Name = FirstName + ' ' + LastName; -"); +GO -migrationBuilder.DropColumn( - name: "FirstName", - table: "Customer"); +INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) +VALUES (N'20200604212813_InitialCreate', N'3.1.4'); -migrationBuilder.DropColumn( - name: "LastName", - table: "Customer"); +GO ``` -> [!TIP] -> The migration scaffolding process warns when an operation might result in data loss (like dropping a column). If you see that warning, be especially sure to review the migrations code for accuracy. - -Apply the migration to the database using the appropriate command. +The script contains three parts: -### [.NET Core CLI](#tab/dotnet-core-cli) +1. The migrations history table is created; this table will store all migrations applied to this database. It only occurs only in the very first migration. +2. Our `Blogs` table is created, based on our code model. This is the actual migration action. +3. A row is inserted into the migrations history table, to record that the **InitialCreate** migration was applied. -```dotnetcli -dotnet ef database update -``` +### Apply the script to your database -### [Visual Studio](#tab/vs) +After we've examined the SQL script and are satisfied with it, we can execute it on our empty database. How this is done varies across databases, but with SQL Server you can use `sqlcmd`: -``` powershell -Update-Database +```console +sqlcmd -S -U -d -i InitialCreate.sql ``` -*** - -### Empty migrations - -Sometimes it's useful to add a migration without making any model changes. In this case, adding a new migration creates code files with empty classes. You can customize this migration to perform operations that don't directly relate to the EF Core model. Some things you might want to manage this way are: +Congratulations, you've just applied your first migration! -* Full-Text Search -* Functions -* Stored procedures -* Triggers -* Views +### Evolving your model -## Remove a migration +A few days have passed, and you're asked to add a creation timestamp to your blogs. You've done the necessary changes to your application, and your model now looks like this: -Sometimes you add a migration and realize you need to make additional changes to your EF Core model before applying it. To remove the last migration, use this command. - -### [.NET Core CLI](#tab/dotnet-core-cli) - -```dotnetcli -dotnet ef migrations remove -``` - -### [Visual Studio](#tab/vs) - -``` powershell -Remove-Migration +```c# +public class Blog +{ + public int Id { get; set; } + public string Name { get; set; } + public DateTime CreatedTimestamp { get; set; } +} ``` -*** +Your model and your production database are now out of sync - we must add a new column to your database schema. Let's create a new migration for this: -After removing the migration, you can make the additional model changes and add it again. -## Revert a migration - -If you already applied a migration (or several migrations) to the database but need to revert it, you can use the same command to apply migrations, but specify the name of the migration you want to roll back to. - -### [.NET Core CLI](#tab/dotnet-core-cli) +#### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli -dotnet ef database update LastGoodMigration +dotnet ef migrations add AddBlogCreatedTimestamp ``` -### [Visual Studio](#tab/vs) +#### [Visual Studio](#tab/vs) ``` powershell -Update-Database LastGoodMigration +Add-Migration AddBlogCreatedTimestamp ``` *** -## Generate SQL scripts - -When debugging your migrations or deploying them to a production database, it's useful to generate a SQL script. The script can then be further reviewed for accuracy and tuned to fit the needs of a production database. The script can also be used in conjunction with a deployment technology. The basic command is as follows. - -### [.NET Core CLI](#tab/dotnet-core-cli) +Note that we give migrations a descriptive name, to make it easier to understand the project history later. Since this isn't the project's first migration, EF Core now compares your updated model against a snapshot of the old model, before the column was added; the model snapshot is one of the files generated by EF Core when you add a migration, and is checked into source control. Based on that comparison, EF Core detects that a column has been added, and adds the appropriate migration. -#### Basic Usage -```dotnetcli -dotnet ef migrations script -``` +We now want to generate an SQL script, just like before. However, the **InitialCreate** migration has already been applied to our database, so our new script should contain only the schema changes since that point: -#### With From (to implied) -This will generate a SQL script from this migration to the latest migration. -```dotnetcli -dotnet ef migrations script 20190725054716_Add_new_tables -``` +#### [.NET Core CLI](#tab/dotnet-core-cli) -#### With From and To -This will generate a SQL script from the `from` migration to the specified `to` migration. ```dotnetcli -dotnet ef migrations script 20190725054716_Add_new_tables 20190829031257_Add_audit_table +dotnet ef migrations script -o AddBlogCreatedTimestamp.sql InitialCreate ``` -You can use a `from` that is newer than the `to` in order to generate a rollback script. *Please take note of potential data loss scenarios.* +#### [Visual Studio](#tab/vs) -### [Visual Studio](#tab/vs) - -#### Basic Usage ``` powershell -Script-Migration -``` - -#### With From (to implied) -This will generate a SQL script from this migration to the latest migration. -```powershell -Script-Migration 20190725054716_Add_new_tables +Script-Migration -Output AddBlogCreatedTimestamp.sql InitialCreate ``` -#### With From and To -This will generate a SQL script from the `from` migration to the specified `to` migration. -```powershell -Script-Migration 20190725054716_Add_new_tables 20190829031257_Add_audit_table -``` -You can use a `from` that is newer than the `to` in order to generate a rollback script. *Please take note of potential data loss scenarios.* - *** -There are several options to this command. - -The **from** migration should be the last migration applied to the database before running the script. If no migrations have been applied, specify `0` (this is the default). - -The **to** migration is the last migration that will be applied to the database after running the script. This defaults to the last migration in your project. +Note the new parameter, which instructs EF Core to generate a script *since* the given migration. Our new SQL script should look the following: -An **idempotent** script can optionally be generated. This script only applies migrations if they haven't already been applied to the database. This is useful if you don't exactly know what the last migration applied to the database was or if you are deploying to multiple databases that may each be at a different migration. -## Apply migrations at runtime +```sql +ALTER TABLE [Blogs] ADD [CreatedTimestamp] datetime2 NOT NULL DEFAULT '0001-01-01T00:00:00.0000000'; -Some apps may want to apply migrations at runtime during startup or first run. Do this using the `Migrate()` method. +GO -This method builds on top of the `IMigrator` service, which can be used for more advanced scenarios. Use `myDbContext.GetInfrastructure().GetService()` to access it. +INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) +VALUES (N'20200604214444_AddBlogCreatedTimestamp', N'3.1.4'); -``` csharp -myDbContext.Database.Migrate(); +GO ``` -> [!WARNING] -> -> * This approach isn't for everyone. While it's great for apps with a local database, most applications will require more robust deployment strategy like generating SQL scripts. -> * Don't call `EnsureCreated()` before `Migrate()`. `EnsureCreated()` bypasses Migrations to create the schema, which causes `Migrate()` to fail. +The script first adds our new column to the database, and then records that the migration has been applied in the migrations history table. -## Next steps +### Next steps -For more information, see . +The above was only a brief introduction to migrations, please consult the other documentation pages to learn more about [managing migrations](xref:core/managing-schemas/migrations/managing), [applying them](xref:core/managing-schemas/migrations/applying), and other aspects. The [.NET Core CLI tool reference](xref:core/miscellaneous/cli/index) also contains useful information on the different commands diff --git a/entity-framework/core/managing-schemas/migrations/managing.md b/entity-framework/core/managing-schemas/migrations/managing.md new file mode 100644 index 0000000000..dc87922ff0 --- /dev/null +++ b/entity-framework/core/managing-schemas/migrations/managing.md @@ -0,0 +1,201 @@ +--- +title: Managing Migrations - EF Core +author: bricelam +ms.author: bricelam +ms.date: 05/06/2020 +uid: core/managing-schemas/migrations/managing +--- +# Managing Migrations + +As your model changes, migrations are added and removed as part of normal development, and the results are checked into your project's source control. To manage migrations, you must first install the [EF Core command-line tools](xref:core/miscellaneous/cli/index). + +> [!TIP] +> If the `DbContext` is in a different assembly than the startup project, you can explicitly specify the target and startup projects in either the [Package Manager Console tools](xref:core/miscellaneous/cli/powershell#target-and-startup-project) or the [.NET Core CLI tools](xref:core/miscellaneous/cli/dotnet#target-project-and-startup-project). + +## Add a migration + +After your model has been changed, you can add a migration for that change: + +### [.NET Core CLI](#tab/dotnet-core-cli) + +```dotnetcli +dotnet ef migrations add AddCreatedTimestamp +``` + +### [Visual Studio](#tab/vs) + +``` powershell +Add-Migration AddCreatedTimestamp +``` + +*** + +The migration name can be used like a commit message in a version control system. For example, you might choose a name like *AddBlogCreatedTimestamp* if the change is a new `CreatedTimestamp` property on your `Blog` entity. + +Three files are added to your project under the **Migrations** directory: + +* **XXXXXXXXXXXXXX_AddCreatedTimestamp.cs**--The main migrations file. Contains the operations necessary to apply the migration (in `Up()`) and to revert it (in `Down()`). +* **XXXXXXXXXXXXXX_AddCreatedTimestamp.Designer.cs**--The migrations metadata file. Contains information used by EF. +* **MyContextModelSnapshot.cs**--A snapshot of your current model. Used to determine what changed when adding the next migration. + +The timestamp in the filename helps keep them ordered chronologically so you can see the progression of changes. + +### Namespaces + +You are free to move Migrations files and change their namespace manually. New migrations are created as siblings of the last migration. + +Alternatively you can use `-Namespace` (Package Manager Console) or `--namespace` (.NET Core CLI) to specify the namespace at generation time. + +### [.NET Core CLI](#tab/dotnet-core-cli) + +```dotnetcli +dotnet ef migrations add InitialCreate --namespace Your.Namespace +``` + +### [Visual Studio](#tab/vs) + +``` powershell +Add-Migration InitialCreate -Namespace Your.Namespace +``` + +*** + +## Customize migration code + +While EF Core generally creates accurate migrations, you should always review the code and make sure it corresponds to the desired change. Although migration code is generated by EF Core, in many cases it is good practice to edit them and customize them appropriately. + +### Column renames + +One notable examine where customizing migrations is required is when renaming a property. For example, if you rename a property from `Name` to `FullName`, EF Core will generate the following migration: + +```c# +migrationBuilder.DropColumn( + name: "Name", + table: "Customers"); + +migrationBuilder.AddColumn( + name: "FullName", + table: "Customers", + nullable: true); +``` + +If applied as-is, this migration will cause you to lose all your customer names; EF Core is unable to know when the intention is to rename a column, and when it is the intention to drop and create a new column. In these cases, modify the generated migration as follows: + +```c# +migrationBuilder.RenameColumn( + name: "Name", + table: "Customers", + newName: "FullName"); +``` + +### Adding raw SQL + +While renaming a column can be achieved via a built-in API, in many cases that is not possible. For example, we may want to replace existing `FirstName` and `LastColumn` properties with a single, new `FullName` property. The migration generated by EF Core will be the following: + +``` csharp +migrationBuilder.DropColumn( + name: "FirstName", + table: "Customer"); + +migrationBuilder.DropColumn( + name: "LastName", + table: "Customer"); + +migrationBuilder.AddColumn( + name: "Name", + table: "Customer", + nullable: true); +``` + +As before, this would cause unwanted data loss. To transfer the data from the old columns, we rearrange the migrations and introduce a raw SQL operation as follows: + +``` csharp +migrationBuilder.AddColumn( + name: "Name", + table: "Customer", + nullable: true); + +migrationBuilder.Sql( +@" + UPDATE Customer + SET Name = FirstName + ' ' + LastName; +"); + +migrationBuilder.DropColumn( + name: "FirstName", + table: "Customer"); + +migrationBuilder.DropColumn( + name: "LastName", + table: "Customer"); +``` + +> [!TIP] +> The migration scaffolding process warns when an operation might result in data loss (like dropping a column). If you see that warning, be especially sure to review the migrations code for accuracy. + +### Arbitrary changes via raw SQL + +Raw SQL can also be used to manage database objects that EF Core isn't aware of. To do this, add a migration without making any model change; an empty migration will be generated, which you can populate with raw SQL operations. + +For example, the following migration creates a SQL Server stored procedure: + +```c# +migrationBuilder.Sql( +@" + CREATE PROCEDURE getFullName + @LastName nvarchar(50), + @FirstName nvarchar(50) + AS + RETURN @LastName + @FirstName; +"); +``` + +This can be used to manage any aspect of your database, including: + +* Stored procedures +* Full-Text Search +* Functions +* Triggers +* Views + +## Remove a migration + +Sometimes you add a migration and realize you need to make additional changes to your EF Core model before applying it. To remove the last migration, use this command. + +### [.NET Core CLI](#tab/dotnet-core-cli) + +```dotnetcli +dotnet ef migrations remove +``` + +### [Visual Studio](#tab/vs) + +``` powershell +Remove-Migration +``` + +*** + +After removing the migration, you can make the additional model changes and add it again. + +> [!WARNING] +> Take care not to remove any migrations which are already applied to production databases. + +## Listing migrations + +You can list all existing migrations as follows: + +```dotnetcli +dotnet ef migrations list +``` + +## Resetting all migrations + +In some extreme cases, it may be necessary to remove all migrations and start over. This can be easily done by deleting your **Migrations** folder and dropping your database. At that point you can create a new initial migration, which will contain you entire current schema. + +It's also possible to reset all migrations and create a single one without losing your data. This is sometimes called "squashing", and involves some manual work: + +* Delete your **Migrations** folder +* Create a new migration and generate a SQL script for it +* In your database, delete all rows from the migrations history table +* Insert a single row into the migrations history - this is the last operation in the SQL script generated above. diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index 048af9ba24..56bf42e863 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -141,6 +141,10 @@ items: - name: Overview href: core/managing-schemas/migrations/index.md + - name: Managing migrations + href: core/managing-schemas/migrations/managing.md + - name: Applying migrations + href: core/managing-schemas/migrations/applying.md - name: Team environments href: core/managing-schemas/migrations/teams.md - name: Custom operations From ed314d8efaf4a7786fe7e1b2771f0b90615b2f67 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 8 Jun 2020 20:41:17 +0200 Subject: [PATCH 2/5] Some refinements --- .../managing-schemas/migrations/applying.md | 52 +++++++++++-------- .../core/managing-schemas/migrations/index.md | 26 ++++++---- .../managing-schemas/migrations/managing.md | 28 +++++----- 3 files changed, 59 insertions(+), 47 deletions(-) diff --git a/entity-framework/core/managing-schemas/migrations/applying.md b/entity-framework/core/managing-schemas/migrations/applying.md index fbb2ebbe61..45c8c2d709 100644 --- a/entity-framework/core/managing-schemas/migrations/applying.md +++ b/entity-framework/core/managing-schemas/migrations/applying.md @@ -10,7 +10,7 @@ uid: core/managing-schemas/migrations/applying Once your migrations have been added, they need to be deployed and applied to your databases. There are various strategies for doing this, with some being more appropriate for production environments, and others for the development lifecycle. > [!NOTE] -> Whatever your deployment strategy, always inspect the generated migrations and test them applying to a production database. A migration may drop a column when the intent was to rename it, or may fail for various when applied to a database. +> Whatever your deployment strategy, always inspect the generated migrations and test them applying to a production database. A migration may drop a column when the intent was to rename it, or may fail for various reasons when applied to a database. ## SQL scripts @@ -18,7 +18,7 @@ The recommended way to deploy migrations to a production database is by generati * SQL scripts can be reviewed for accuracy; this is important since applying schema changes to production databases is a potentially dangerous operation that could involve data loss. * In some cases, the scripts can be tuned to fit the specific needs of a production database. -* SQL scripts can be used in conjunction with a deployment technology. +* SQL scripts can be used in conjunction with a deployment technology, and can even be generated as part of your CI process. * SQL scripts can be provided to a DBA, and can be managed and archived separately. ### [.NET Core CLI](#tab/dotnet-core-cli) @@ -41,27 +41,30 @@ dotnet ef migrations script AddNewTables #### With From and To -The following generates a SQL script from the `from` migration to the specified `to` migration. +The following generates a SQL script from the specified `from` migration to the specified `to` migration. ```dotnetcli dotnet ef migrations script AddNewTables AddAuditTable ``` -You can use a `from` that is newer than the `to` in order to generate a rollback script. *Please take note of potential data loss scenarios.* +You can use a `from` that is newer than the `to` in order to generate a rollback script. -### [Visual Studio](#tab/vs) +> [!WARNING] +> Please take note of potential data loss scenarios. -The following generates a SQL script from a blank database to the latest migration: +### [Visual Studio](#tab/vs) #### Basic Usage +The following generates a SQL script from a blank database to the latest migration: + ``` powershell Script-Migration ``` #### With From (to implied) -The following generates a SQL script from this migration to the latest migration. +The following generates a SQL script from the given migration to the latest migration. ```powershell Script-Migration AddNewTables @@ -69,7 +72,7 @@ Script-Migration AddNewTables #### With From and To -The following generates a SQL script from the `from` migration to the specified `to` migration. +The following generates a SQL script from the specified `from` migration to the specified `to` migration. ```powershell Script-Migration AddNewTables AddAuditTable @@ -78,15 +81,14 @@ You can use a `from` that is newer than the `to` in order to generate a rollback *** -There are several options to this command. - -The **from** migration should be the last migration applied to the database before running the script. If no migrations have been applied, specify `0` (this is the default). +Script generation accepts the following two arguments in indicate which range of migrations should be generated: -The **to** migration is the last migration that will be applied to the database after running the script. This defaults to the last migration in your project. +* The **from** migration should be the last migration applied to the database before running the script. If no migrations have been applied, specify `0` (this is the default). +* The **to** migration is the last migration that will be applied to the database after running the script. This defaults to the last migration in your project. ## Idempotent SQL scripts -The SQL scripts generated above can only be applied to change your schema from one migration to another; it is your responsibility to apply the script appropriately, and only to database in the correct migration state. EF Core also supports generating **idempotent** scripts, which internally check which migrations have already been applied, and only apply missing ones. This is useful if you don't exactly know what the last migration applied to the database was, or if you are deploying to multiple databases that may each be at a different migration. +The SQL scripts generated above can only be applied to change your schema from one migration to another; it is your responsibility to apply the script appropriately, and only to database in the correct migration state. EF Core also supports generating **idempotent** scripts, which internally check which migrations have already been applied (via the migrations history table), and only apply missing ones. This is useful if you don't exactly know what the last migration applied to the database was, or if you are deploying to multiple databases that may each be at a different migration. The following generates idempotent migrations: @@ -102,14 +104,14 @@ dotnet ef migrations add AddNewTables --idempotent Add-Migration AddNewTables -Idempotent ``` -> [!WARNING] +> [!WARNING] > Idempotent scripts have some known limitations and will not work in all scenarios. *** ## Command-line tools -The EF command-line tools can be used to apply migrations to a database. While productive for local development and testing of migrations, this approach is inappropriate for management of production databases: +The EF command-line tools can be used to apply migrations to a database. While productive for local development and testing of migrations, this approach isn't ideal for managing production databases: * The SQL commands are applied directly by the tool, without giving the developer a change to inspect or modify them. This can be dangerous in a production environment. * The .NET SDK and the EF tool must be installed on production servers. @@ -128,6 +130,11 @@ The following updates your database to a given migration: dotnet ef database update AddNewTables ``` +Note that this can be used to roll back to an earlier migration as well. + +> [!WARNING] +> Please take note of potential data loss scenarios. + ### [Visual Studio](#tab/vs) The following updates your database to the latest migration: @@ -142,23 +149,26 @@ The following updates your database to a given migration: Update-Database AddNewTables ``` -*** +Note that this can be used to roll back to an earlier migration as well. + +> [!WARNING] +> Please take note of potential data loss scenarios. -Note that this can be used to roll back to an earlier migration as well. *Please take note of potential data loss scenarios.* +*** For more information on applying migrations via the command-line tools, see the [EF Core tools reference](xref:core/miscellaneous/cli/index). ## Apply migrations at runtime -It's possible for the application itself to apply migrations programmatically, typically during startup. While productive for local development and testing of migrations, this approach is inappropriate for management of production databases: +It's possible for the application itself to apply migrations programmatically, typically during startup. While productive for local development and testing of migrations, this approach is inappropriate for managing production databases, for the following reasons: * If multiple instances of your application are running, both applications could attempt to apply the migration concurrently and fail (or worse, cause data corruption). * Similarly, if an application is accessing the database while another application migrates it, this can cause severe issues. -* This requires the application to have elevated access to modify the database schema. It's generally good practice to limit the application's database permissions in production. +* The application must have elevated access to modify the database schema. It's generally good practice to limit the application's database permissions in production. * It's important to be able to roll back an applied migration in case of an issue. The other strategies provide this easily and out of the box. * The SQL commands are applied directly by the program, without giving the developer a change to inspect or modify them. This can be dangerous in a production environment. -To apply migrations programmatically, call `myDbContext.Database.Migrate()`. For example, a typical ASP.NET application can do the following: +To apply migrations programmatically, call `context.Database.Migrate()`. For example, a typical ASP.NET application can do the following: ```c# public static void Main(string[] args) @@ -179,5 +189,5 @@ Note that `Migrate()` builds on top of the `IMigrator` service, which can be use > [!WARNING] > -> * Carefully consider before using this approach in production. Experience has shown that the simplicity of this deployment strategy is outweighed by the problem it brings. Consider using SQL scripts instead. +> * Carefully consider before using this approach in production. Experience has shown that the simplicity of this deployment strategy is outweighed by the issues it creates. Consider using SQL scripts instead. > * Don't call `EnsureCreated()` before `Migrate()`. `EnsureCreated()` bypasses Migrations to create the schema, which causes `Migrate()` to fail. diff --git a/entity-framework/core/managing-schemas/migrations/index.md b/entity-framework/core/managing-schemas/migrations/index.md index 002cb98dab..ae9b54124c 100644 --- a/entity-framework/core/managing-schemas/migrations/index.md +++ b/entity-framework/core/managing-schemas/migrations/index.md @@ -12,9 +12,11 @@ In real life projects, data models change as features get implemented: new entit At a high level, migrations functions in the following way: * When a data model change is introduced, the developer uses EF Core tools to add a corresponding migration describing the updates necessary to keep the database schema in sync. EF Core compares the current model against a snapshot of the old model to find out the differences, and generates migration source files; the files are kept in your project's source control like any other source file. -* Once a new migration has been generated, it can be deployed to a database in various ways. EF Core uses a migrations history table in the database which records all migrations which have already been applied; this allows EF Core to know which state your database is in. +* Once a new migration has been generated, it can be applied to a database in various ways. EF Core records all applied migrations in a special history table, allowing it to know which migrations have been applied and which haven't. -## Tutorial +The rest of this page is a step-by-step beginner's guide for using migrations. Consult the other pages in this section for more in-depth information. + +## Getting started Let's assume you've just completed your first EF Core application, which contains the following simple model: @@ -26,7 +28,7 @@ public class Blog } ``` -During development, you may have used the [Create and Drop APIs](xref:core/managing-schemas/ensure-created) to iterate quickly; but now that your application is going to production, you need a way to evolve the schema without dropping the entire database. +During development, you may have used the [Create and Drop APIs](xref:core/managing-schemas/ensure-created) to iterate quickly, changing your model as needed; but now that your application is going to production, you need a way to safely evolve the schema without dropping the entire database. ### Install the tools @@ -37,7 +39,7 @@ First, you'll have to install the [EF Core command-line tools](xref:core/miscell ### Create your first migration -You're now ready to add your first migration! Instruct EF Core to create a migrations named **InitialCreate**: +You're now ready to add your first migration! Instruct EF Core to create a migration named **InitialCreate**: #### [.NET Core CLI](#tab/dotnet-core-cli) @@ -53,11 +55,11 @@ Add-Migration InitialCreate *** -EF Core will create a directory called **Migrations**, and generated some files. In general, it's a good idea to inspect what exactly EF Core generated - and possibly amend it - but we'll skip over that for now. +EF Core will create a directory called **Migrations** in your project, and generate some files. It's a good idea to inspect what exactly EF Core generated - and possibly amend it - but we'll skip over that for now. ### Create a migration SQL script -You now want to create your first production database and apply your migration there. In production scenarios, you typically need to create the database yourself, e.g. by using a cloud service user interface, or asking your DBA. Once an empty database is available, you can generate an *SQL script* from the migration we've just created: +You now want to create your first production database and apply your migration there. In production scenarios, you typically need to create the database yourself, e.g. by using a cloud service user interface, or asking your DBA. Once an empty database is available, you can generate a *SQL script* from the migration we've just created: #### [.NET Core CLI](#tab/dotnet-core-cli) @@ -102,7 +104,7 @@ GO The script contains three parts: -1. The migrations history table is created; this table will store all migrations applied to this database. It only occurs only in the very first migration. +1. The migrations history table is created; this table will store all migrations applied to this database. This only happens in your very first migration. 2. Our `Blogs` table is created, based on our code model. This is the actual migration action. 3. A row is inserted into the migrations history table, to record that the **InitialCreate** migration was applied. @@ -114,7 +116,7 @@ After we've examined the SQL script and are satisfied with it, we can execute it sqlcmd -S -U -d -i InitialCreate.sql ``` -Congratulations, you've just applied your first migration! +Congratulations, you've just applied your first migration! If you now connect to your database with a tool such as SQL Server Management Studio, you should see your table. ### Evolving your model @@ -146,9 +148,11 @@ Add-Migration AddBlogCreatedTimestamp *** -Note that we give migrations a descriptive name, to make it easier to understand the project history later. Since this isn't the project's first migration, EF Core now compares your updated model against a snapshot of the old model, before the column was added; the model snapshot is one of the files generated by EF Core when you add a migration, and is checked into source control. Based on that comparison, EF Core detects that a column has been added, and adds the appropriate migration. +Note that we give migrations a descriptive name, to make it easier to understand the project history later. + +Since this isn't the project's first migration, EF Core now compares your updated model against a snapshot of the old model, before the column was added; the model snapshot is one of the files generated by EF Core when you add a migration, and is checked into source control. Based on that comparison, EF Core detects that a column has been added, and adds the appropriate migration. -We now want to generate an SQL script, just like before. However, the **InitialCreate** migration has already been applied to our database, so our new script should contain only the schema changes since that point: +We now want to generate a SQL script, just like before. However, the **InitialCreate** migration has already been applied to our database, so our new script should contain only the schema changes since that point: #### [.NET Core CLI](#tab/dotnet-core-cli) @@ -181,4 +185,4 @@ The script first adds our new column to the database, and then records that the ### Next steps -The above was only a brief introduction to migrations, please consult the other documentation pages to learn more about [managing migrations](xref:core/managing-schemas/migrations/managing), [applying them](xref:core/managing-schemas/migrations/applying), and other aspects. The [.NET Core CLI tool reference](xref:core/miscellaneous/cli/index) also contains useful information on the different commands +The above was only a brief introduction to migrations. Please consult the other documentation pages to learn more about [managing migrations](xref:core/managing-schemas/migrations/managing), [applying them](xref:core/managing-schemas/migrations/applying), and other aspects. The [.NET Core CLI tool reference](xref:core/miscellaneous/cli/index) also contains useful information on the different commands diff --git a/entity-framework/core/managing-schemas/migrations/managing.md b/entity-framework/core/managing-schemas/migrations/managing.md index dc87922ff0..1ae9f8f1a4 100644 --- a/entity-framework/core/managing-schemas/migrations/managing.md +++ b/entity-framework/core/managing-schemas/migrations/managing.md @@ -7,7 +7,7 @@ uid: core/managing-schemas/migrations/managing --- # Managing Migrations -As your model changes, migrations are added and removed as part of normal development, and the results are checked into your project's source control. To manage migrations, you must first install the [EF Core command-line tools](xref:core/miscellaneous/cli/index). +As your model changes, migrations are added and removed as part of normal development, and the migration files are checked into your project's source control. To manage migrations, you must first install the [EF Core command-line tools](xref:core/miscellaneous/cli/index). > [!TIP] > If the `DbContext` is in a different assembly than the startup project, you can explicitly specify the target and startup projects in either the [Package Manager Console tools](xref:core/miscellaneous/cli/powershell#target-and-startup-project) or the [.NET Core CLI tools](xref:core/miscellaneous/cli/dotnet#target-project-and-startup-project). @@ -19,13 +19,13 @@ After your model has been changed, you can add a migration for that change: ### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli -dotnet ef migrations add AddCreatedTimestamp +dotnet ef migrations add AddBlogCreatedTimestamp ``` ### [Visual Studio](#tab/vs) ``` powershell -Add-Migration AddCreatedTimestamp +Add-Migration AddBlogCreatedTimestamp ``` *** @@ -34,7 +34,7 @@ The migration name can be used like a commit message in a version control system Three files are added to your project under the **Migrations** directory: -* **XXXXXXXXXXXXXX_AddCreatedTimestamp.cs**--The main migrations file. Contains the operations necessary to apply the migration (in `Up()`) and to revert it (in `Down()`). +* **XXXXXXXXXXXXXX_AddCreatedTimestamp.cs**--The main migrations file. Contains the operations necessary to apply the migration (in `Up`) and to revert it (in `Down`). * **XXXXXXXXXXXXXX_AddCreatedTimestamp.Designer.cs**--The migrations metadata file. Contains information used by EF. * **MyContextModelSnapshot.cs**--A snapshot of your current model. Used to determine what changed when adding the next migration. @@ -42,9 +42,7 @@ The timestamp in the filename helps keep them ordered chronologically so you can ### Namespaces -You are free to move Migrations files and change their namespace manually. New migrations are created as siblings of the last migration. - -Alternatively you can use `-Namespace` (Package Manager Console) or `--namespace` (.NET Core CLI) to specify the namespace at generation time. +You are free to move Migrations files and change their namespace manually. New migrations are created as siblings of the last migration. Alternatively, you can specify the namespace at generation time as follows: ### [.NET Core CLI](#tab/dotnet-core-cli) @@ -62,7 +60,7 @@ Add-Migration InitialCreate -Namespace Your.Namespace ## Customize migration code -While EF Core generally creates accurate migrations, you should always review the code and make sure it corresponds to the desired change. Although migration code is generated by EF Core, in many cases it is good practice to edit them and customize them appropriately. +While EF Core generally creates accurate migrations, you should always review the code and make sure it corresponds to the desired change; in some cases, it is even necessary to do so. ### Column renames @@ -79,7 +77,7 @@ migrationBuilder.AddColumn( nullable: true); ``` -If applied as-is, this migration will cause you to lose all your customer names; EF Core is unable to know when the intention is to rename a column, and when it is the intention to drop and create a new column. In these cases, modify the generated migration as follows: +EF Core is generally unable to know when the intention is to drop a column and create a new one (two separate changes), and when a column should be renamed. If the above migration is applied as-is, all your customer names will be lost. To rename a column, replace the above generated migration with the following: ```c# migrationBuilder.RenameColumn( @@ -88,6 +86,9 @@ migrationBuilder.RenameColumn( newName: "FullName"); ``` +> [!TIP] +> The migration scaffolding process warns when an operation might result in data loss (like dropping a column). If you see that warning, be especially sure to review the migrations code for accuracy. + ### Adding raw SQL While renaming a column can be achieved via a built-in API, in many cases that is not possible. For example, we may want to replace existing `FirstName` and `LastColumn` properties with a single, new `FullName` property. The migration generated by EF Core will be the following: @@ -130,12 +131,9 @@ migrationBuilder.DropColumn( table: "Customer"); ``` -> [!TIP] -> The migration scaffolding process warns when an operation might result in data loss (like dropping a column). If you see that warning, be especially sure to review the migrations code for accuracy. - ### Arbitrary changes via raw SQL -Raw SQL can also be used to manage database objects that EF Core isn't aware of. To do this, add a migration without making any model change; an empty migration will be generated, which you can populate with raw SQL operations. +Raw SQL can also be used to manage database objects that EF Core isn't aware of. To do this, add a migration without making any model change; an empty migration will be generated, which you can then populate with raw SQL operations. For example, the following migration creates a SQL Server stored procedure: @@ -191,11 +189,11 @@ dotnet ef migrations list ## Resetting all migrations -In some extreme cases, it may be necessary to remove all migrations and start over. This can be easily done by deleting your **Migrations** folder and dropping your database. At that point you can create a new initial migration, which will contain you entire current schema. +In some extreme cases, it may be necessary to remove all migrations and start over. This can be easily done by deleting your **Migrations** folder and dropping your database; at that point you can create a new initial migration, which will contain you entire current schema. It's also possible to reset all migrations and create a single one without losing your data. This is sometimes called "squashing", and involves some manual work: * Delete your **Migrations** folder * Create a new migration and generate a SQL script for it * In your database, delete all rows from the migrations history table -* Insert a single row into the migrations history - this is the last operation in the SQL script generated above. +* Insert a single row into the migrations history, to record that the first migration has already been applied, since your tables are already there. The insert SEQL is the last operation in the SQL script generated above. From 6c1d4e318e418fce28f5b05e7f0d9e13892e8a39 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Sat, 27 Jun 2020 22:46:37 +0200 Subject: [PATCH 3/5] Address review comments by Jeremy --- .../core/managing-schemas/migrations/applying.md | 2 +- entity-framework/core/managing-schemas/migrations/index.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/entity-framework/core/managing-schemas/migrations/applying.md b/entity-framework/core/managing-schemas/migrations/applying.md index 45c8c2d709..855569b8aa 100644 --- a/entity-framework/core/managing-schemas/migrations/applying.md +++ b/entity-framework/core/managing-schemas/migrations/applying.md @@ -10,7 +10,7 @@ uid: core/managing-schemas/migrations/applying Once your migrations have been added, they need to be deployed and applied to your databases. There are various strategies for doing this, with some being more appropriate for production environments, and others for the development lifecycle. > [!NOTE] -> Whatever your deployment strategy, always inspect the generated migrations and test them applying to a production database. A migration may drop a column when the intent was to rename it, or may fail for various reasons when applied to a database. +> Whatever your deployment strategy, always inspect the generated migrations and test them before applying to a production database. A migration may drop a column when the intent was to rename it, or may fail for various reasons when applied to a database. ## SQL scripts diff --git a/entity-framework/core/managing-schemas/migrations/index.md b/entity-framework/core/managing-schemas/migrations/index.md index ae9b54124c..ce9fae06f9 100644 --- a/entity-framework/core/managing-schemas/migrations/index.md +++ b/entity-framework/core/managing-schemas/migrations/index.md @@ -7,11 +7,11 @@ uid: core/managing-schemas/migrations/index --- # Migrations Overview -In real life projects, data models change as features get implemented: new entities or properties are added and removed, and databases schema needs to be changed accordingly to be kept in sync with the application. The migrations feature in EF Core provides a way to incrementally update the database schema to keep it in sync with the application's data model while preserving existing data in the database. +In real world projects, data models change as features get implemented: new entities or properties are added and removed, and database schemas needs to be changed accordingly to be kept in sync with the application. The migrations feature in EF Core provides a way to incrementally update the database schema to keep it in sync with the application's data model while preserving existing data in the database. -At a high level, migrations functions in the following way: +At a high level, migrations function in the following way: -* When a data model change is introduced, the developer uses EF Core tools to add a corresponding migration describing the updates necessary to keep the database schema in sync. EF Core compares the current model against a snapshot of the old model to find out the differences, and generates migration source files; the files are kept in your project's source control like any other source file. +* When a data model change is introduced, the developer uses EF Core tools to add a corresponding migration describing the updates necessary to keep the database schema in sync. EF Core compares the current model against a snapshot of the old model to determine the differences, and generates migration source files; the files can be tracked in your project's source control like any other source file. * Once a new migration has been generated, it can be applied to a database in various ways. EF Core records all applied migrations in a special history table, allowing it to know which migrations have been applied and which haven't. The rest of this page is a step-by-step beginner's guide for using migrations. Consult the other pages in this section for more in-depth information. From b212d391a25a491f8bdebdc0080e927d758b9243 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Sat, 27 Jun 2020 23:10:56 +0200 Subject: [PATCH 4/5] Change tutorial to show dotnet migrations instead of SQL scripts --- .../managing-schemas/migrations/applying.md | 3 - .../core/managing-schemas/migrations/index.md | 75 +++---------------- 2 files changed, 9 insertions(+), 69 deletions(-) diff --git a/entity-framework/core/managing-schemas/migrations/applying.md b/entity-framework/core/managing-schemas/migrations/applying.md index 855569b8aa..1ab3d51fb5 100644 --- a/entity-framework/core/managing-schemas/migrations/applying.md +++ b/entity-framework/core/managing-schemas/migrations/applying.md @@ -104,9 +104,6 @@ dotnet ef migrations add AddNewTables --idempotent Add-Migration AddNewTables -Idempotent ``` -> [!WARNING] -> Idempotent scripts have some known limitations and will not work in all scenarios. - *** ## Command-line tools diff --git a/entity-framework/core/managing-schemas/migrations/index.md b/entity-framework/core/managing-schemas/migrations/index.md index ce9fae06f9..e38acb4a59 100644 --- a/entity-framework/core/managing-schemas/migrations/index.md +++ b/entity-framework/core/managing-schemas/migrations/index.md @@ -57,66 +57,24 @@ Add-Migration InitialCreate EF Core will create a directory called **Migrations** in your project, and generate some files. It's a good idea to inspect what exactly EF Core generated - and possibly amend it - but we'll skip over that for now. -### Create a migration SQL script +### Create your database and schema -You now want to create your first production database and apply your migration there. In production scenarios, you typically need to create the database yourself, e.g. by using a cloud service user interface, or asking your DBA. Once an empty database is available, you can generate a *SQL script* from the migration we've just created: +At this point you can have EF create your database and create your schema from the migration. This is as simple as doing the following: #### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli -dotnet ef migrations script -o InitialCreate.sql +dotnet ef migrations update ``` #### [Visual Studio](#tab/vs) ``` powershell -Script-Migration -Output InitialCreate.sql +Update-Database ``` *** -You now have an **InitialCreate.sql** script which can be executed against your empty database to create the schema corresponding to your model. If you're using SQL Server, the script should resemble the following: - -```sql -IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL -BEGIN - CREATE TABLE [__EFMigrationsHistory] ( - [MigrationId] nvarchar(150) NOT NULL, - [ProductVersion] nvarchar(32) NOT NULL, - CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) - ); -END; - -GO - -CREATE TABLE [Blogs] ( - [Id] int NOT NULL IDENTITY, - [Name] nvarchar(max) NULL, - CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id]) -); - -GO - -INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) -VALUES (N'20200604212813_InitialCreate', N'3.1.4'); - -GO -``` - -The script contains three parts: - -1. The migrations history table is created; this table will store all migrations applied to this database. This only happens in your very first migration. -2. Our `Blogs` table is created, based on our code model. This is the actual migration action. -3. A row is inserted into the migrations history table, to record that the **InitialCreate** migration was applied. - -### Apply the script to your database - -After we've examined the SQL script and are satisfied with it, we can execute it on our empty database. How this is done varies across databases, but with SQL Server you can use `sqlcmd`: - -```console -sqlcmd -S -U -d -i InitialCreate.sql -``` - -Congratulations, you've just applied your first migration! If you now connect to your database with a tool such as SQL Server Management Studio, you should see your table. +That's all there is to it - your application is ready to run on your new database, and you didn't need to write a single line of SQL. Note that this way of applying migrations is ideal for local development, but is less suitable for production environments - see the [Applying Migrations page](xref:core/managing-schemas/migrations/applying) for more info. ### Evolving your model @@ -133,7 +91,6 @@ public class Blog Your model and your production database are now out of sync - we must add a new column to your database schema. Let's create a new migration for this: - #### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli @@ -152,36 +109,22 @@ Note that we give migrations a descriptive name, to make it easier to understand Since this isn't the project's first migration, EF Core now compares your updated model against a snapshot of the old model, before the column was added; the model snapshot is one of the files generated by EF Core when you add a migration, and is checked into source control. Based on that comparison, EF Core detects that a column has been added, and adds the appropriate migration. -We now want to generate a SQL script, just like before. However, the **InitialCreate** migration has already been applied to our database, so our new script should contain only the schema changes since that point: +You can now apply your migration as before: #### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli -dotnet ef migrations script -o AddBlogCreatedTimestamp.sql InitialCreate +dotnet ef migrations update ``` #### [Visual Studio](#tab/vs) ``` powershell -Script-Migration -Output AddBlogCreatedTimestamp.sql InitialCreate +Update-Database ``` *** -Note the new parameter, which instructs EF Core to generate a script *since* the given migration. Our new SQL script should look the following: - - -```sql -ALTER TABLE [Blogs] ADD [CreatedTimestamp] datetime2 NOT NULL DEFAULT '0001-01-01T00:00:00.0000000'; - -GO - -INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) -VALUES (N'20200604214444_AddBlogCreatedTimestamp', N'3.1.4'); - -GO -``` - -The script first adds our new column to the database, and then records that the migration has been applied in the migrations history table. +Note that this time, EF detects that the database already exists. In addition, when our first migration was applied above, this fact was recorded in a special migrations history table in your database; this allows EF to automatically apply only the new migration. ### Next steps From 6712e2f9c94d1d3a397093bedf53868cc3ad2c98 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 30 Jun 2020 01:34:31 +0200 Subject: [PATCH 5/5] Address review comments by Brice --- .../core/managing-schemas/migrations/applying.md | 4 ++-- .../core/managing-schemas/migrations/index.md | 6 +++--- .../core/managing-schemas/migrations/managing.md | 13 ++++++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/entity-framework/core/managing-schemas/migrations/applying.md b/entity-framework/core/managing-schemas/migrations/applying.md index 1ab3d51fb5..0b7f292e24 100644 --- a/entity-framework/core/managing-schemas/migrations/applying.md +++ b/entity-framework/core/managing-schemas/migrations/applying.md @@ -95,13 +95,13 @@ The following generates idempotent migrations: #### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli -dotnet ef migrations add AddNewTables --idempotent +dotnet ef migrations script --idempotent ``` #### [Visual Studio](#tab/vs) ``` powershell -Add-Migration AddNewTables -Idempotent +Script-Migration -Idempotent ``` *** diff --git a/entity-framework/core/managing-schemas/migrations/index.md b/entity-framework/core/managing-schemas/migrations/index.md index e38acb4a59..2a60bd7efc 100644 --- a/entity-framework/core/managing-schemas/migrations/index.md +++ b/entity-framework/core/managing-schemas/migrations/index.md @@ -59,12 +59,12 @@ EF Core will create a directory called **Migrations** in your project, and gener ### Create your database and schema -At this point you can have EF create your database and create your schema from the migration. This is as simple as doing the following: +At this point you can have EF create your database and create your schema from the migration. This can be done via the following: #### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli -dotnet ef migrations update +dotnet ef database update ``` #### [Visual Studio](#tab/vs) @@ -114,7 +114,7 @@ You can now apply your migration as before: #### [.NET Core CLI](#tab/dotnet-core-cli) ```dotnetcli -dotnet ef migrations update +dotnet ef database update ``` #### [Visual Studio](#tab/vs) diff --git a/entity-framework/core/managing-schemas/migrations/managing.md b/entity-framework/core/managing-schemas/migrations/managing.md index 1ae9f8f1a4..544beabf67 100644 --- a/entity-framework/core/managing-schemas/migrations/managing.md +++ b/entity-framework/core/managing-schemas/migrations/managing.md @@ -64,7 +64,7 @@ While EF Core generally creates accurate migrations, you should always review th ### Column renames -One notable examine where customizing migrations is required is when renaming a property. For example, if you rename a property from `Name` to `FullName`, EF Core will generate the following migration: +One notable example where customizing migrations is required is when renaming a property. For example, if you rename a property from `Name` to `FullName`, EF Core will generate the following migration: ```c# migrationBuilder.DropColumn( @@ -140,12 +140,11 @@ For example, the following migration creates a SQL Server stored procedure: ```c# migrationBuilder.Sql( @" - CREATE PROCEDURE getFullName + EXEC ('CREATE PROCEDURE getFullName @LastName nvarchar(50), @FirstName nvarchar(50) AS - RETURN @LastName + @FirstName; -"); + RETURN @LastName + @FirstName;')"); ``` This can be used to manage any aspect of your database, including: @@ -156,6 +155,10 @@ This can be used to manage any aspect of your database, including: * Triggers * Views +In most cases, EF Core will automatically wrap each migration in its own transaction when applying migrations. Unfortunately, some migrations operations cannot be performed within a transaction in some databases; for these cases, you may opt out of the transaction by passing `suppressTransaction: true` to `migrationBuilder.Sql`. + +If the `DbContext` is in a different assembly than the startup project, you can explicitly specify the target and startup projects in either the [Package Manager Console tools](xref:core/miscellaneous/cli/powershell#target-and-startup-project) or the [.NET Core CLI tools](xref:core/miscellaneous/cli/dotnet#target-project-and-startup-project). + ## Remove a migration Sometimes you add a migration and realize you need to make additional changes to your EF Core model before applying it. To remove the last migration, use this command. @@ -177,7 +180,7 @@ Remove-Migration After removing the migration, you can make the additional model changes and add it again. > [!WARNING] -> Take care not to remove any migrations which are already applied to production databases. +> Take care not to remove any migrations which are already applied to production databases. Not doing so will prevent you from being able to revert it, and may break the assumptions made by subsequent migrations. ## Listing migrations