I have a Razor Pages website application and I'd like to move my database code to a separate project/assembly, which is referenced from my main project/assembly.
Creating a new class project and moving the files from my Data and Model folders is straight forward. But I'm not clear on where my connection string goes (currently, it's in the appsettings.json for my main project).
How do I specify the connection string for my class library?
The connection string should be configured in the same project where the services connect to the DbContext, so you can leave the appsettings.json as-is.
It is the configuring project (the one that is setting up all the dependencies) that sets the connection to the DB, and the EF migration tool needs the connection to track and apply changes. Any assembly can be used to store migrations, but the EF tool needs to be invoked for a project with an actual connection.
EF Core uses Dependency Injection to configure services for runtime which includes setting the connection string for any DB. The control of how the DB classes interact with their environment is given to the app that is running it, which allows for the same DB code to be used across multiple instances, states and even providers. EF Core uses the current state & provider of the DB where it is deployed to determine changes and scaffolding, so it can only create migrations with a configured instance of a DbContext connected to a DB (usually the development instance).
When a solution is comprised multiple dependent services with a common data model that will need the same migrations, only one of the projects in the solution should be responsible for managing DB state. Whichever project is chosen, it needs to create a DBContext with a valid connection when it starts up for the EF tools to work. ASP.NET Core uses the Microsoft.Extensions.Configuration package and the UseStartup method to make the configuration simple. This can be your existing UI project that would read the connection string from existing settings and pass it to your CustomDbContext at Startup. The EF Tools CLI will use the default profile (the Green run arrow) to get the settings from launchSettings.json and appSettings.json to connect to the DB. The configuration should be in place in each environment you deploy to so that the migrations can be run from the same configuring project and applied as needed.
You can avoid ASP.NET and create a custom startup class in your data package that runs to apply migrations, but this is a lot of extra work for something already in the box. The DbContext class does have an OnConfiguring method that can be used to set the connection. Placing configuration inside of code limits where the software can run, so it should still be set externally.
The DbContext can be referenced from another package:
The DbContext and Models can be defined in a separate 'pure' project, then referenced in the Startup like so:
using mysolution.Data.CustomDbContext;
...
services.AddDbContext<CustomDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("defaultConnection")));
Configure the DbContext to run and where to store migrations:
The tricky part is applying migrations if you use them. If your Razor assembly was named 'mysolution_UI' and your data project is 'mysolution_Data'. Move the Data, Models, Migrations to mysolution_Data and add this to the startup in mysolution_UI project:
services.AddDbContext<CustomDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("defaultConnection")
, b => b.MigrationsAssembly("mysolution_Data")));
Then when adding or deploying the package, the migrations should be invoked from the 'mysolution_UI' project.
Add-Migration NewMigration -Project mysolution_UI
This allows multiple projects to use the data package for the entities connected to the same DB, but only one is responsible for maintaining the migrations.
Related
I've created three new .NET 7 projects:
API
Database
Worker
In my Database project, I have my DbContext set up. The API and Worker project both have a project reference to the Database project.
In my API project (using minimal hosting model), I simply configure the database connection like this:
var builder = WebApplication.CreateBuilder(args);
....
....
....
builder.Services.AddDbContext<EnergyPricesContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))
);
However, my Worker project is a console application, so I cannot simply do the above line, because there is no builder, no dependency injection, and there is also no appsettings.json file in that project.
I thought about creating a bootstrap project, which would have the appsettings.json file as well as a "Startup" file that all projects have a reference to. However, I feel like that's a bad idea.
What's best practise when it comes to multiple projects and referencing the same appsetting.json file, if that's even the correct way to do it?
I have a website application. Depending on the IsDemoSite setting in my appsettings.json file, the application uses one of two different database connection strings. (One for my main site, and another for our demo site.)
I also have a class library that contains all the Entity Framework models and migrations.
In the Package Manager Console, I set the Default project to the class library.
Then, I can run the add-migration and update-database commands on that class library. But here's the kicker: The IsDemoSite setting for my main application determines which database these commands work with.
How on Earth does Package Manager Console know to what connection string is used by my main application based on the current setting? I'm not running the main application. Package Manager Console is not using the main application as the default project. How the heck does it know which connection string to use?
When you run and add-migration or an update-database command, Package Manager Console will look for the Startup project of your solution and use it as "entry point" for these commands.
Probably inside your Startup.cs class you have the database context injected using the connection string that is stored in your appsettings.json.
I believe you have something like that:
string connectionString;
bool isDemoSite = configuration.GetValue<string>("IsDemoSite");
if(isDemoSite)
connectionString = configuration.GetConnectionString("mainSite");
else
connectionString = configuration.GetConnectionString("demoSite");
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));
add-migration and update-database uses this very same code to determinate against which database it will execute, is something like your application is beign executed to allow this commands to run.
That's also the reason you need some EntityFramework packages installed in your startup project.
I was wondering which appsettings.json would the application use if i used Package Manager Console from Visual Studio 2022. I had appsettings.json, appsettings.Development.json and appsettings.Production.json, each with different connection string.
The one used was appsettings.Development.json.
I am very familiar with Entity Framework using Database First approach and how to deploy the solution with it.
Basically, in my solution with database first approach, I have a web client project that consumes data access library project that is coded with database first approach.
So, first, I write some SQL Server scripts to add new tables (or make schema changes).
Next, go to the data access library project, using EF edmx designer to update .net from existing database, compile this data access layer, and the DDL reference is automatically updated in the client web project.
When I deploy the solution to the production server:
First, I need to run the t-SQL scripts on the production SQL server
Next, I deploy the 2 updated DDLs (one for the web and 1 for the data access layer) on the web server.
Now, I have a new application that includes a web project and a data access layer project that uses EF Code First approach.
I am new to EF code first approach. I know any time when I change the database schema, for instance adding a new table, I need to run code first migration in the Package Management Console in Visual Studio to let my back-end database instance change/update.
My question:
When I deploy the application to the production, what are the steps I should follow?
How is the production SQL server updated that is created with EF Code First approach?
Is it a automatic process or I have to run the migration manually like I do inside Visual Studio under the Package Management Console?
Thanks.
If you're using Azure then you can configure it has automatic process as shown below.
Else you have to do it manually like this :
You have to create a db script and after that you can run it on your production db.
PM> Update-Database -Script
You can refer this doc : Getting a SQL Script
Another option where I normaley use :
When I need to run migrations aginst the production db,I change my conn string to reflect production db and after that run :
PM> Update-Database
You have several options with migrations.
You can generate a script using Update-Database -Script (as #Sampath notes)
You can run Update-Database -ConnectionString="YourDbString" and it will do it against the production database for you
You can use a migration initializer and on app startup it will use the applications connection string to run the migration. Do this by putting a line similar to this in your initialization routine:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>());
Where Context is your DbContext type and Configuration is the configuration class generated when you made the first migration.
See this MSDN article for more information: https://msdn.microsoft.com/en-us/data/jj591621.aspx
I've got this error for the 762nd time but this time I am getting it as soon as I attempt to access my Production site, straight after deleting the 'production' database on Azure and then publishing my site.
The model backing the 'PropertyContext' context has changed since the database was created. Consider using Code First Migrations to update the database
I deleted the database because I couldn't fix this issue any other way but it still doesn't work.
Some important points:
I'm using EF6 and publishing to Azure.
This is 1 of 2 projects/sites that uses the same Repo project. I have no
problems with the other one, just this one.
I have tried publishing the problem project first (after deleting the db) and
second with the same result.
I have tried deleting both WEBSITES and the DB from Azure and starting again
I have tried deleting all migrations and starting with a fresh data model
I have tried the following in my Global.asax (in both projects)
Database.SetInitializer PropertyContext>(null); <-- SO won't let me put the first <
and
Database.SetInitializer(new MigrateDatabaseToLatestVersion<PropertyContext, MyConfiguration>());
new PropertyContext().Database.Initialize(true);
I'm using .net 4.5
Why am I getting this error on a new database and how can I get this site to work?
Just ran into the same error in ASP.Net application. In my case I did not use Code First, but I used standard ASP.Net authentication provider which apparently uses Code First, and authentication was broken because of this issue.
Here is quick and dirty solution is you don't care much about existing user records:
For me the solution was to drop the dbo.__MigrationHistory table, authentication started working fine after that. Be aware! This solution is not for everyone! This will fix the problem, but it is potentially risky.
If you cannot afford to lose data in AspNet* tables:
ASP.Net authentication provider automatically creates tables in your database:
AspNetRoles
AspNetUsers
AspNetUserRoles
AspNetUserClaims
AspNetUserLogings
The tables are empty by default, if you haven't created any new logins for your web site, you can use "quick and dirty" solution above. If you do care about preserving user information or just curios how Code First migrations work, follow these steps:
Open your Web.config file and check the name of the connection string you have for your database. It will be one of the records under <connectionStrings> element.
Open Package Manager Console:
Tools –> Library Package Manager –> Package Manager Console
In Package Manager Console window, use a drop-down to set Default Project. Make sure this is the project that contains ASP.Net authentication provider code.
Execute command:
Update-Database -ConnectionStringName MyConnectionStringName
Replace the MyConnectionStringName with the actual name you looked up in web.config.
As a result of this command you will see a new folder "Migrations" with a bunch of code generated by the Update-Database command. Re-build and re-deploy your app, your new migration code will be executed on startup and would bring the database schema in sync with an updated version of ASP.Net authentication provider code.
When using Code First with Migrations, your database creates a table called __MigrationHistory to track the current schema. When you run your application your Entity Framework will check this table to make sure that the database schema matches your database entities. If they do not match, you will get this error.
To update your database follow these steps:
Open the Package Manager Console (View -> Other Windows -> Package Manager Console) in Visual Studio
In the Package Manager Console Window, there is a drop down with your projects in, make sure it is set to the project that contains your DbContext
Make sure that the project that contains your App.Config / Web.Config file is "Set as Startup Project" (If you have multiple Configs, it must be the one with the Database Connection String defined.
Type Update-Database -ConnectionStringName MyConnString where MyConnString is the name (not the actual connection string) of your connection string in your App.Config / Web.Config
If you get an error like this: "Unable to update database to match the current model because there are pending changes and automatic migration is disabled."
You should enable Automatic Migrations and try again.
To enable Automatic Migrations
In the Migrations folder (in the project with your DbContext), open Configuration.cs.
Make sure the Constructor contains: AutomaticMigrationsEnabled = true;
To stop Entity Framework/DbContext from monitoring changes on your database you could simply delete the __MigrationHistory table in your database. It is then up to you to make sure that the database remains updated manually.
MSDN article here
The solution from this is to use the static method SetInitializer and bind to the context a Null value. If you are working on a Web solution, the best position to write the code is in the Application_Start of your Global.asax.cs file.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
//...
Database.SetInitializer<MyContext>(null);
}
I got a similar problem this morning. Suddenly the error appeared and couldn't be resolved:
The model backing the 'ApplicationDbContext' context has changed since
the database was created. Consider using Code First Migrations to update
the database
I have one project for MVC and another project for the model, context and repositories. I've been working on it for weeks but today it said stop.
I have tried to delete database, enable-migration, add-migration and update-database so many times that I've lost count. I've added initializers to MigrateDatabaseToLatestVersion as well as DropCreateDatabaseIfModelChanges. All in vain...
What finally made it work was to move model, context and repositories into the MVC project (not something I was keen on)...then it worked right out of the box without any code changes at all (besides namespaces)! Very strange...
I've read so many blog posts during the day trying to solve this problem. One of them (I don't know which one) mentioned a bug in Visual Studio 2013 where reference to DLL files weren't always updated as they should, suggesting that my MVC project missed out something when I was running add-migration and update-database in my separate project. But it's just a guess.
I'm using EF 6.1 and .Net 4.5.1 in my solution.
Got a similar problem! Answer is here
http://www.asp.net/mvc/overview/older-versions/getting-started-with-aspnet-mvc3/cs/adding-a-new-field
(Rick Anderson)
There are two approaches to resolving the error:
Have the Entity Framework automatically drop and re-create the database based on the new model class schema. This approach is very convenient when doing active development on a test database, because it allows you to quickly evolve the model and database schema together. The downside, though, is that you lose existing data in the database — so you don't want to use this approach on a production database!
Explicitly modify the schema of the existing database so that it matches the model classes. The advantage of this approach is that you keep your data. You can make this change either manually or by creating a database change script.
I have spent some hours trying to solve this problem. One project was working, the other one wasn't.
I had different projects referencing different versions of Entity Framework. In my case, I had a Console app and a Windows Service app, both referencing a third project containing code first classes and DbContext.
After running Update-Package EntityFramework everything worked fine in both projects.
I have ASP.NET MVC4 app with Entity Framework Code First approach. I've moved my DbContext inheritor to separate Model project recently (I've copied connection string from web.config to the app.config).
Now when I'm trying to run my app I've got error that my database should be created directly through Code First or Migrations. First way is not suitable for me because I have remote DB server (I've created it through hoster's control panel).
But when I'm trying to enable Migrations I've got error that No context type was found in the assembly 'MyProject'. This is obviously happen because my DbContext inheritor not placed in the start project.
So how can I indicate to look context class in separate project?
By the way, I have DropCreateDatabaseIfModelChanges<> initializer for my DbContext inheritor.
In the Package Manager Console, if you run Get-Help Enable-Migrations, it will show you all of the advanced options. Included in those are:
-ProjectName (the project to run this command against, i.e. to look for the context type)
-StartupProjectName (the project which has the app.config/web.config where the context runs, i.e. where your connection string lives). This one is important unless your Model project has the correct connection string in its own .config file.
-ConnectionString (the connection string to use while scaffolding the migration if you want to override the value)
When you're using Add-Migration it should support the same options.
You can also change the Package Manager Console's Default Project dropdown to run against your model project by default.
If you are using Package Manager Console you can choose a default project where entity framework will search your DbContext.