{"id":14245,"date":"2022-03-02T09:41:24","date_gmt":"2022-03-02T17:41:24","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cse\/?p=14245"},"modified":"2023-06-19T11:09:14","modified_gmt":"2023-06-19T18:09:14","slug":"entity-framework-journey","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/entity-framework-journey\/","title":{"rendered":"Entity Framework Journey"},"content":{"rendered":"<h2>Purpose<\/h2>\n<p>As an Engineering team on Microsoft\u2019s Commercial Software Engineering (CSE), we strive to empower customers to build and maintain their software-based solutions. A key factor in being successful in our goal is to educate, upskill and develop the solution by applying certain Engineering Fundamentals.<\/p>\n<p>Engineering Fundamentals are essential principles and characteristics that contribute to high quality enterprise solutions. These include:<\/p>\n<ul>\n<li>An organized and well-defined backlog that captures the features the team will build<\/li>\n<li>Tooling for the team to manage the code base, and introduce mechanisms for code reviews<\/li>\n<li>Designing the solution and the engineering processes with Security from the beginning<\/li>\n<li>Quality rigor through the form of testability and code coverage<\/li>\n<li>Observability mechanisms that allow the team to analyze usage trends, troubleshoot issues, and identify opportunities for improvement<\/li>\n<li>A seamless developer experience that maximizes the productivity of the engineering team<\/li>\n<li>CICD (Continuous Integration and Continuous Delivery) to have a consistent process to take code contributions and seamlessly deploy the updated solution to an environment<\/li>\n<\/ul>\n<p><!--StartFragment --><\/p>\n<p class=\"pf0\"><span class=\"cf0\">This article is a part of a series of articles where we dive deep into one of these Engineering Fundamentals. <\/span><\/p>\n<p class=\"pf0\"><span class=\"cf0\">Each article will share the team\u2019s journey, challenges, and learnings to apply each principle alongside the customer\u2019s team. <\/span><\/p>\n<p class=\"pf0\"><span class=\"cf0\">Other articles in this series are:<\/span><\/p>\n<ul>\n<li class=\"pf0\"><a href=\"https:\/\/devblogs.microsoft.com\/cse\/2022\/03\/02\/continuous-integration-and-deployment-journey\/\"><span class=\"cf0\">Continuous Integration and Deployment<\/span><\/a><\/li>\n<li class=\"pf0\"><a href=\"https:\/\/devblogs.microsoft.com\/cse\/2022\/03\/02\/observability-journey\/\"><span class=\"cf0\">Observability<\/span><\/a><\/li>\n<\/ul>\n<p class=\"pf0\"><span class=\"cf0\">In this article, we will cover d<\/span><span class=\"cf0\">atabase change management using Entity Framework<\/span><\/p>\n<p class=\"pf0\"><span class=\"cf0\">.<\/span><\/p>\n<p><!--EndFragment --><\/p>\n<h2>Introduction<\/h2>\n<p>Our team had an opportunity to develop a Web Application (WebApp) intended to leverage an Object-Relational-Mapper (ORM) to define our data models. We also wanted to seamlessly interact with the ORM directly within our codebase. The purpose of this content is to share our journey and how we planned for where an ORM fits within the CICD pipeline.<\/p>\n<p>Throughout this section, we\u2019ll share details on how we accomplished our goals, the challenges that surfaced, and things worth thinking about if you envision your team working on similar efforts. But to start, let\u2019s cover our guiding considerations and motivations for this effort.<\/p>\n<p>This article is not intended to present the advantages\/disadvantages of using ORMs, whether managing DB Schema changes should be part of a CICD flow or not, nor to explore alternatives to manage your DB Schema. I encourage you to perform more focused research on this effort before adopting this design pattern.<\/p>\n<p>With that said, we were already leaning on using an ORM and embedding DB Schema changes as part of our CICD flow. Before jumping to solutioning, as a team we defined the following key motivations and requirements that we wanted to hold ourselves accountable for:<\/p>\n<ol>\n<li>Allow the Database Schema and Application \u2018versioning\u2019 to evolve independently of one another.<\/li>\n<li>Ability to easily map what versions of the Database Schema are compatible with a particular Application version, and vice versa.<\/li>\n<li>Have good developer experience and enable \u2018rapid\u2019 development prior to the first production release.<\/li>\n<li>Production Database Schema changes can <strong>only<\/strong> be applied manually.<\/li>\n<li>Production Database Schema changes should be applied using the <strong>same<\/strong> script and process used in a lower environment, that resulted in a successful deployment.<\/li>\n<\/ol>\n<p>Ease of applying changes to the DB Schema while incorporating versioning. Changes may include applying changes (going to a newer version), or reverting changes (reverting to a previous version).<\/p>\n<h2>Objectives<\/h2>\n<p>Our tech stack was based on .NET Core, with a SQL Database (DB). Therefore, we naturally gravitated towards using <strong>Entity Framework (EF)<\/strong> for our ORM.<\/p>\n<p>The <a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/managing-schemas\/\">Microsoft Entity Framework Core documentation<\/a> outlines the two primary ways for keeping the application code in sync with the DB schema:<\/p>\n<ol>\n<li>Migrations \u2013 definition and overview found <a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/managing-schemas\/migrations\/?tabs=dotnet-core-cli\">here<\/a><\/li>\n<li>Reverse Engineering \u2013 definition and overview found <a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/managing-schemas\/scaffolding?tabs=dotnet-core-cli\">here<\/a><\/li>\n<\/ol>\n<p>We recommend considering your organization\u2019s Software Development processes, DevOps and DevSecOps processes to balance the pros and cons before choosing the appropriate option. On our team, we elected to go with the <strong>migrations<\/strong> strategy, as this provided the desired behavior of having the DB schema evolve alongside the codebase.<\/p>\n<p>Before describing our approach, I want to paint a very high-level visual of how <strong>EF Migrations<\/strong> work.<\/p>\n<p><strong>Key players\/components:<\/strong><\/p>\n<ul>\n<li>The Developer writing code as part of the WebApp that will serve as the \u201cservice owner,\u201d the person ultimately responsible for the DB data and schema<\/li>\n<li>The DB<\/li>\n<\/ul>\n<p><strong>Key pieces:<\/strong><\/p>\n<ul>\n<li>The WebApp and Entity Framework model code<\/li>\n<li>The EF Migration directory, containing all the various EF Migration files, as part of the codebase<\/li>\n<li>The DB\u2019s \u201cEF Migrations History\u201d Table<\/li>\n<\/ul>\n<p>The Interaction between the players and the key pieces are as follows:<\/p>\n<ul>\n<li>For each \u201cbatch\u201d of <u>EF model code changes<\/u> performed by the <u>Developer<\/u> (creating a new table, renaming a table or column, etc.), the <u>Developer<\/u> will create a new <u>migration<\/u> that captures this change<\/li>\n<li>For each <u>migration<\/u> created by the <u>Developer<\/u>, there will be a corresponding <u>migrations file <\/u>which instructs <u>EF<\/u> of the operations it has to perform on the <u>DB<\/u> to either:\n<ul>\n<li>Upgrade to this new version<\/li>\n<li>Downgrade to a previous version from this version as defined by the m<u>igration file<\/u><\/li>\n<\/ul>\n<\/li>\n<li>The <u>DB\u2019s \u201cEF Migrations History\u201d table<\/u> will inform <u>EF<\/u> what the current migration version the DB Schema is, along with an audit log of when and what migration version any DB Schema migration change was performed<\/li>\n<li><u>EF<\/u> will read this <u>\u201cEF Migrations History\u201d DB table<\/u> to determine how many <u>migrations<\/u> are needed to go from the current <u>DB<\/u> Schema state to the desired state. Once <u>EF<\/u> knows this information, it will execute the operations as outlined by each <u>migration<\/u>, which also updates the <u>\u201cEF Migrations History\u201d DB table<\/u>, until it reaches the desired state.<\/li>\n<\/ul>\n<p><strong>Note:<\/strong> Having the complete history of all migration Files and the <u>\u201cEF Migrations History\u201d DB table <\/u>enables applying changes on top of the current schema or reverting\/rolling back schema changes to any previous state.<\/p>\n<h2>Solution<\/h2>\n<p>The pattern that we applied was to <strong>not use migrations<\/strong> until the team determined that we were close to deploying the first release to production.<\/p>\n<p>This offered the following advantages:<\/p>\n<ol>\n<li>The team did not have to create a lot of migrations \u2013 which, given the frequency of DB model changes early on, would have resulted in many migrations\n<ol>\n<li>Instead, the team preferred to re-initialize the DB whenever a schema change was made by deleting the schema and running the application. On startup, the application would initialize the DB with the latest schema<\/li>\n<\/ol>\n<\/li>\n<li>It would be a low-cost effort when transitioning to migrations (with the important reminder to ensure to <a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/managing-schemas\/ensure-created\">not use \u201cEnsureCreated\u201d alongside migrations<\/a>)<\/li>\n<\/ol>\n<p>It is important to note how invaluable it was for the team to undergo the manual steps required to create, review, commit, and apply migrations to a database. Namely, they allow for the ability to:<\/p>\n<ol>\n<li>Demonstrate the CLI dependencies and CLI commands involved in the various processes<\/li>\n<li>Allow the team to practice performing manual \u201cchecks\u201d prior to having them be a part of the CICD pipeline. Two essential \u201cchecks\u201d are: to review DB changes before applying them in a non-production environment, and to review changes before letting a DB Admin apply them in a production environment<\/li>\n<\/ol>\n<blockquote>\n<p style=\"text-align: center;\"><em>A crucial take-away is that once you <strong>start<\/strong> managing your DB schema with <u>migrations<\/u>, you should <strong>only<\/strong> use migrations to alter the DB schema.<\/em><\/p>\n<\/blockquote>\n<p>The primary reason for this is that, from the very first migration created, the DB Schema\u2019s \u201cHistory\u201d is now version-controlled as a part of the codebase. This means that, as with any other code versioning solution, altering the history outside of the provided tooling can have drastic implications, resulting in \u201cversion conflicts\u201d between:<\/p>\n<ul>\n<li>The application version and the DB Schema version<\/li>\n<li>The current DB Schema version, and its desired \u201ctarget\u201d version<\/li>\n<\/ul>\n<p>What could be the business impact, you ask? Bad deployments that could lead to application outages, failures, errors, or <strong>data loss<\/strong><\/p>\n<h2>.NET Core Web App Design<\/h2>\n<p>To support creating EF Migrations, the WebApp had to be designed with the intention to influence how the application would start up, given different environment variables\/runtime configurations.<\/p>\n<p>Specifically, we wanted to use the <a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/cli\/dotnet\"><strong>EF Dotnet CLI<\/strong><\/a>, which can only create migrations by having the application startup and successfully connect to the targeted DB on a locally hosted environment. This may pose a challenge if the WebApp has additional external hard dependencies. For example: any external service or component that would prevent the application from starting up if improperly configured.<\/p>\n<p>The design that we chose was to have a specific \u201cDebugEF\u201d runtime that would start the application in a \u201cbarebones\u201d state \u2013 one without any external dependencies besides the DB. Thanks to our adoption of <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/dependency-injection?view=aspnetcore-5.0\">Dependency Injection<\/a> (DI), this approach resulted in no code changes outside of the \u201cstartup\u201d file in .NET Core.<\/p>\n<p>Below is an example of a .NET Core WebApp\u2019s <em>Startup.cs <\/em>file, which is where the application\u2019s startup configurations are defined. Notice how we leveraged <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/preprocessor-directives\">.NET preprocessor directives<\/a> in order to avoid starting the application with all the external dependencies when running against an \u201cDebugEF\u201d run configuration.<\/p>\n<p>&nbsp;<\/p>\n<blockquote>\n<p style=\"text-align: center;\"><strong><em>Note:<\/em><\/strong><em> Be careful not to abuse or overuse preprocessor directives, as they can lead to challenges when it comes to code maintainability and readability.<\/em><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-2.png\"><img decoding=\"async\" class=\"alignnone size-large wp-image-14246\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-2-1024x614.png\" alt=\"Image ef migrations configuration 2\" width=\"640\" height=\"384\" srcset=\"https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-2-1024x614.png 1024w, https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-2-300x180.png 300w, https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-2-768x460.png 768w, https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-2.png 1430w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-1.png\"><img decoding=\"async\" class=\"alignnone size-large wp-image-14247\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-1.png\" alt=\"Image ef migrations configuration 1\" width=\"624\" height=\"268\" srcset=\"https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-1.png 624w, https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-configuration-1-300x129.png 300w\" sizes=\"(max-width: 624px) 100vw, 624px\" \/><\/a><\/p>\n<p>All that is required by the developer is to set the values for the required environment variables: \u201cSQL-SERVER-FQDN\u201d and \u201cSQL-DB-NAME\u201d<\/p>\n<p>This design would then allow the development team the ability to use the <em>EF DotNet CLI<\/em> to:<\/p>\n<ul>\n<li>create migrations targeting a specific DB using the following command: <code>dotnet ef migrations add &lt;name-of-migration-to-create&gt; --configuration DebugEF<\/code><\/li>\n<\/ul>\n<ul>\n<li>apply Migrations targeting a specific DB using the following command: <code>dotnet ef database update\u00a0 &lt;name-of-migration-to-apply&gt; --configuration DebugEF<\/code><\/li>\n<\/ul>\n<h2>Overall Flow<\/h2>\n<p>Although we have not gone live to production yet, we intentionally decided not to automate the DB Change Management for production environments. This is due to the severe implications of a bad change being introduced and the probability of this occurring.<\/p>\n<p>Instead, we planned on automating the DB change management in lower lifecycle environments (still using migrations) before applying the application changes on top of it. This would allow us the ability to validate that a DB (regardless of the current migration it is on) could be promoted to the latest migration. Upon validating this, the CICD flow would be allowed to proceed with all our application-specific workflow items (linting, building, unit testing, packaging, deploying, integration tests).<\/p>\n<p>The flow can be visualized in the Appendix below. This section will provide a description of each step.<\/p>\n<h3>Assumptions<\/h3>\n<ul>\n<li>At least one individual has access to the various DB Server instances<\/li>\n<li>Once EF Migrations are adopted, the various DB Schema instances are initialized and maintained using the EF Migrations CLI. This flow is <strong>not applicable<\/strong> until EF Migrations are a part of the development efforts<\/li>\n<li>Developers can run the application using a configuration \/ runtime that has no external dependencies (with exception of the DB context \/ dependency)<\/li>\n<\/ul>\n<h3>Steps in the Flow<\/h3>\n<p>All commands are assumed to be executed in the same path where the \u201cStartup.cs\u201d file is found in.<\/p>\n<h4>Development \/ PR Creation<\/h4>\n<p>These steps are all done from a developer\u2019s perspective, using their own <u>unique DB instance<\/u>:<\/p>\n<ol>\n<li>A User Story is picked up, one that is known to include a DB Schema change.<\/li>\n<li>The Developer creates their own feature branch and pulls it down locally<\/li>\n<li>The <strong>necessary environment variables are set and defined<\/strong> in such a way that their CLI of choice can pull in those values\n<ol>\n<li>can be done per each CLI instance or done as part of a .<em>bash_profile<\/em> or .<em>bashrc<\/em> for example<\/li>\n<\/ol>\n<\/li>\n<li>The Developer\u2019s <strong>dedicated DB schema is dropped<\/strong>\n<ol>\n<li>At a minimum, all Tables are deleted<\/li>\n<\/ol>\n<\/li>\n<li><strong>Apply the latest migration state<\/strong> (as specified by the codebase) to get the DB initialized. <code>dotnet ef database update --configuration {configuration_value}<\/code><\/li>\n<\/ol>\n<p>This command will leverage the environment variables, from step #2, to go through all the migration Files in the code. It will then apply them 1-by-1 until the DB Schema reflects the latest desired state. This command will also create and populate the \u201cEF migrations\u201d DB table<\/p>\n<ol start=\"6\">\n<li><strong>Develop<\/strong> and perform the necessary application and DB changes<\/li>\n<li><strong>Create<\/strong> a new migration file once you are ready to apply the DB changes: <code>dotnet ef migrations add {name-of-migration} --configuration {configuration_value}<\/code><\/li>\n<\/ol>\n<ol start=\"8\">\n<li><strong>Review<\/strong> the migration code that was generated. This is crucial to <strong>fix any generated code<\/strong> that may result in possible data loss. This <a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/managing-schemas\/migrations\/managing?tabs=dotnet-core-cli\">document<\/a> mentions common scenarios to look out for and options to change them so the desired change is accomplished without data loss.<\/li>\n<li><strong>Apply <\/strong>the DB changes: <code>dotnet ef database update {name-of-migration} --configuration {configuration_value}<\/code><\/li>\n<\/ol>\n<ol start=\"10\">\n<li><strong>Run Integration tests<\/strong> to ensure that the application and DB changes don\u2019t break desired functionality.<\/li>\n<li>If more DB changes are necessary, or if the tests resulted in a failure, <strong>revert the DB change<\/strong>, delete the migration file, and continue to perform more code changes: <code>dotnet ef database update {name-of-previous-migration} --configuration {configuration_value}<\/code><\/li>\n<li><code><\/code><strong style=\"font-size: 1rem;\">Create a PR<\/strong><span style=\"font-size: 1rem;\"> once the DB Change produces a healthy change and that all tests <\/span>pass<span style=\"font-size: 1rem;\">. The PR should contain the newly added migration file.<\/span><\/li>\n<\/ol>\n<h4>Merging PR and Promoting to DEV<\/h4>\n<ol>\n<li>The team <strong>reviews the PR<\/strong>, making sure that the migration file does not include any changes that could cause <a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/managing-schemas\/migrations\/managing?tabs=dotnet-core-cli\">undesired changes or data loss<\/a>. The team <strong>approves the PR<\/strong> once ready<\/li>\n<li>If the CICD doesn\u2019t have the ability to apply the DB change against DEV, then manually ensure that the <strong>DEV DB is updated based on the latest migration file.<\/strong>\n<ul>\n<li>Change the CLI\u2019s environment variables so that EF Migrations use the DEV DB\u2019s connection properties such as: DB Server Fully Qualified Domain Names (FQDN) and DB name: <code>dotnet ef database update {name-of-migration} --configuration {configuration_value}<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<ol start=\"3\">\n<li>The team <strong>merges the PR,<\/strong> which automatically kicks off the CICD pipeline to deploy to DEV<\/li>\n<li>If an issue occurs that requires reverting the PR merge and the CICD doesn\u2019t have the ability to apply the DB change against DEV, then manually <strong>revert the DB change.<\/strong>\n<ul>\n<li>Change the CLI\u2019s environment variables so that EF Migrations use the DEV DB\u2019s connection properties (DB Server FQDN and DB name): <code>dotnet ef database update {name-of-previous-migration} --configuration {configuration_value}<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<ol>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>\n<h2>The team <strong>reverts the merge<\/strong> and kicks off a new CICD deployment to revert the deployment.<\/h2>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h4>Promoting to UAT and PROD<\/h4>\n<p>Unlike with DEV, where migrations can be applied to the DB using the CLI, the upper-lifecycle environments like User Acceptance Testing (UAT) or PROD should have the DB changes applied using a SQL script. This script can be generated, using the EF Migrations CLI, so that the same operations are performed as in lower-lifecycle environments, like DEV.<\/p>\n<ol>\n<li>DB Admin accesses the DB\u2019s \u201cEF Migrations\u201d table to <strong>check what migration reflects<\/strong> the current DB Schema reflects<\/li>\n<li>DB Admin <strong>generates the SQL Script<\/strong> which produces all the operations that will take the DB schema from its current version to the desired one.\n<ul>\n<li>Change the CLI\u2019s environment variables so that EF Migrations use the desired DB\u2019s connection properties (DB Server FQDN and DB name): <code>dotnet ef migrations script {name-of-current-migration} {name-of-desired-migration} --configuration {configuration_value}<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<ol start=\"3\">\n<li>The DB Admin <strong>generates the \u201crevert\u201d SQL Script<\/strong> in case reverting the changes is necessary later: <code>dotnet ef migrations script {name-of-desired-migration} {name-of-current-migration} --configuration {configuration_value}<\/code><\/li>\n<li>The DB Admin <strong>reviews the generated SQL Scripts<\/strong> to ensure they look accurate and safe to execute.<\/li>\n<li>If it looks good, the DB Admin accesses the DB and <strong>executes the SQL Script<\/strong> to change the DB Schema to the new version.<\/li>\n<li>The team <strong>validates that the DB Change didn\u2019t cause an issue<\/strong>\n<ol>\n<li>If an issue surfaces, DB Admin to <strong>revert the DB Change<\/strong> by executing the \u201crevert SQL Script\u201d created earlier.<\/li>\n<\/ol>\n<\/li>\n<li>The team executes the CICD flow or manual runs the process to <strong>promote the solution to the desired environment.<\/strong><\/li>\n<\/ol>\n<\/blockquote>\n<h2>Appendix<\/h2>\n<h2>EF NonProd Migrations Flow<\/h2>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-nonprod-flow.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-14248\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-nonprod-flow.png\" alt=\"Image ef migrations nonprod flow\" width=\"495\" height=\"745\" srcset=\"https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-nonprod-flow.png 495w, https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-nonprod-flow-199x300.png 199w\" sizes=\"(max-width: 495px) 100vw, 495px\" \/><\/a><\/p>\n<h2>EF Prod Migrations Flow<\/h2>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-prod-flow.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-14249\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-prod-flow.png\" alt=\"Image ef migrations prod flow\" width=\"588\" height=\"479\" srcset=\"https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-prod-flow.png 588w, https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2022\/03\/ef-migrations-prod-flow-300x244.png 300w\" sizes=\"(max-width: 588px) 100vw, 588px\" \/><\/a><\/p>\n<h2>Resources<\/h2>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/cli\/dotnet\">DotNet EF CLI<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/managing-schemas\/migrations\/?tabs=dotnet-core-cli\">EF Core Migrations Overview<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/preprocessor-directives\">DotNet Preprocessor Directives<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/dependency-injection?view=aspnetcore-5.0\">Dependency Injection in ASP.NET Core<\/a><\/p>\n<h2>Team Members<\/h2>\n<p>The CSE US Government team below was instrumental in delivering the impact throughout the engagement, and in sharing our journey through the form of this article.<\/p>\n<ul>\n<li>Adrian Gonzalez<\/li>\n<li>David Lambright<\/li>\n<li>Gavin Bauman<\/li>\n<li>James Truitt<\/li>\n<li>Jordon Malcolm<\/li>\n<li>Kristin Ottofy<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>As an Engineering team on Microsoft\u2019s Commercial Software Engineering (CSE), we strive to empower customers to build and maintain their software-based solutions. In this article, we will cover an aspect of our Engineering Fundamentals, DB change management using Entity Framework. <\/p>\n","protected":false},"author":85264,"featured_media":14250,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,17],"tags":[3342,3341,3339,3343,3340],"class_list":["post-14245","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cse","category-frameworks","tag-change-management","tag-db","tag-ef","tag-ef-migrations","tag-entity-framework"],"acf":[],"blog_post_summary":"<p>As an Engineering team on Microsoft\u2019s Commercial Software Engineering (CSE), we strive to empower customers to build and maintain their software-based solutions. In this article, we will cover an aspect of our Engineering Fundamentals, DB change management using Entity Framework. <\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/14245","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/users\/85264"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=14245"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/14245\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/14250"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=14245"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=14245"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=14245"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}