How to explicitly name the database when using Entity Framework Migrations 4.3 - entity-framework

I've recently started using Entity Framework migrations and noticed that the database name is not pulling through for me when I run the Update-Database command.
My connectionstring is:
<connectionStrings>
<add name="DataContext" connectionString="Server=.\SQLEXPRESS;Initial Catalog=TestDB;Trusted_Connection=Yes;" providerName="System.Data.SqlClient" />
</connectionStrings>
The very first time I run Update-Database my database is created with the correct name TestDB. However, as soon as I make a change to one of my entities it will not update any longer for me unless I add a Start Up Project Name (I'm using a multi project solution):
Update-Database -StartUpProjectName "TestDB.Data"
This then makes another new database which migrations will always continue to use. I don't mind having to put in the StartUpProjectName command but is there a way to override the default name for the database this produces? It always creates the database as
TestDB.Data.DataContext
Is there a way to ensure that the database created when passing the StartUpProject name is just called TestDB or is this a limitation of using the StartUpProjectName setting?
As a note, I think the reason I need to specify the StartUpProjectName is that I have a multilayer project setup. The Migrations Configuration file is in my 'Data' project, the entities/models are in my 'Domain' project, etc. I also do not currently have any initialize options in my Global.asax.cs file as I would have used previously on code first ef 4.2. So in my project I just have a DataContext in my Data project and the Migrations Configuration in that project also.
EDIT:
Since I originally setup this question I stumbled onto the 'correct' way to name a database in a multiproject solution. While the answer below will work it does mean you are duplicating your web.config in another area which isn't an ideal solution. Instead you can just put the name into your DbContext by doing something like this (DataContext is just the name I used in my project):
public class DataContext : DbContext
{
public DataContext() : base("DatabaseNameHere")
{ }
public DbSet<Table1> Table1 { get; set; }
public DbSet<Table2> Table2 { get; set; }
public virtual void Commit()
{
base.SaveChanges();
}
}
Thanks,
Rich

You can avoid managing it in app.config by offering it as a parameter:
Update-Database -Verbose
-ConnectionString "CONNECTIONSTRING"
-ConnectionProviderName "System.Data.SqlClient"
-StartupProjectName WEBSITE_PROJECT -ProjectName MIGRATION_PROJECT
Easy-piezy, if you love to type endlessly.

When doing update-database you should specify the project that contains the migrations. Make sure that you have an app.config file in that project that contains the correct connection string.
When splitting up an application over several projects, the connection string used when running the app is the one of the project started. When migrating, the connection string used is the one of the project containing the migrations.
When I did a similar setup I had to add the connection string in two places. A bit awkward, but it works.

You can have your connection string stored in the web.config in your website project and the DBContext and migration files in another project and still share the same connection string. However you need to make sure that as well as setting the Data project (or whatever project has the DBContext etc. in it) as the default project for the Package Manager Console, you ALSO need to make sure that your website is set to the Default StartUp Project!!!
I cannot see this documented anywhere, but a frantic 24 hours of not being able to figure out why my migrations where suddenly being applied to a SQLExpress db, led me to this conclusion.

I tried with Latest EF5 from Nuget.
However Update-Database does not read the App.config from the project that contain the migrations (just like the answer 1 year ago) but it will only read *.config from start up project. It is great but I discover how Add-Migration and Update-Database find a suitable connection string here:
It trying to get "DefaultConnection" connection string first
Then it is trying to get the connection string name based on context class name. E.g. I have the MyContext class derived from DbContext so I can use the "MyContext" connection string name. Useful when I have multiple db connections.
If both the above connection string names are not found, it will fail and show no "DefaultConnection" connection string unless you supply the -ConnectionStringName parameter. See get-help Update-Database to view the help page in the Package Manager Console.
There is no retry or fallback attempt, so if the "DefaultConnection" contains a wrong connection string, it will simply show an error.
If both DefaultConnection and context name exist in the connection strings, DefaultConnection will take precedence.
I would prefer #2 become the first try because the name is more specific but the above steps is what EF5 Migrations do when trying to connect to the db.

Related

.net core not connecting to the changed database in appsettings.json connectionstrings in visual studio debug

I am working on a .net core project, I wanted to change the connectionstring of the database in appsettings.json.
I had created a duplicate database and named it originalname_fake01 and made a clone of the original database for testing.
I have also changed the database name in appsettings.developement.json. Everything seems fine but when I run the application in debug mode in visual studio. the data was being pulled from the original database rather than the changed database name in appsettings.json.
Here is my appsettings connectionstrings code:
Old connectionstring was
"connectionStrings": {
"MyConnectionString":
"Server=localhost;port=3306;database=mydb;user=root;password=rt123;"
}
changed connection string (new)
"connectionStrings": {
"FakeConnectionString":
"Server=localhost;port=3306;database=mydb_fake01;user=root;password=rt123;"
}
I am not able to understand why it is connecting to the old database rather than the new database even after changing the connectionstring.
Any help would be appreciated.
If you want the development settings to override the production settings you need to use the same names and full path. Your connection string should be named MyConnectionString, not MyConnectionString if you want the DbContext to pick it automatically.
JSON setting files have no special meaning in .NET Core, they are just files. Every provider produces key/value pairs in the form Section1:Subsection1:Attribute1, Value. Newer provider values override earlier values. Providers can be JSON or XML file readers, INI file readers, databases etc. In all cases, the settings are flattened to path/value pairs.
The file
"connectionStrings": {
"MyConnectionString": "Server=localhost;port=3306;database=mydb;user=root;password=rt123;"
}
Produces a value named connectionStrings:MyConnectionString whose value is Server=localhost;port=3306;database=mydb;user=root;password=rt123;. To override this you need to specify a setting with the same path.
The default Host builder specifies some default settings providers. From the docs, those are :
appsettings.json.
appsettings.{Environment}.json.
= Secret Manager when the app runs in the Development environment.
Environment variables.
Command-line arguments.
Settings specified lower down the list override previous ones. This means that on a development machine, the connectionStrings:MyConnectionString in appsettings.Developoment.json overrides the element with the same name in appsettings.json.
This also means that we can override the connection string with an environment variabl or a command-line argument, eg
dotnet run /connectionStrings:MyConnectionString Server=localhost;port=3306;database=mydb;user=root;password=rt123;
I have finally able to find the problem in the dbcontext.cs modelbuilder. There is a code line which has strongly typed Schema Name.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
OnModelCreatingImpl(modelBuilder);
modelBuilder.HasDefaultSchema("MyDB");
}
I changed it use the new schema as below:
modelBuilder.HasDefaultSchema("MyDB_Fake01");
I don't understand why we need to give schema name in both connectionstring and in modelbuilder. I Guess we should avoid explicit schema name targeting in ModelBuilder so that, whenever the connectionstring is changed. it will target the database correctly.
Anyways, the problem is solved as the application is connecting to the intended database.
You are almost there. In your changed connection string (new) setting, change the FakeConnectionString to MyConnectionString. If you have same keys in appsettings.json and in appsettings.development.json then latter will override the former.
"connectionStrings": {
"MyConnectionString": "Server=localhost;port=3306;database=mydb_fake01;user=root;password=rt123;"
}
P.S. This is applicable to any environment not only to development
There is also a file named "secrets.json" which overrides all other appSettings configuration. Make sure it has correct Database name.
The file named "secrets.json" worked for me as the default connection string was hardcoded there pointing to the old database. Editing the connection string (Initial Catalog=dbName) to point to the current database name fixed the problem. Thanks!
sample content of "secrets.jason":
{
"ConnectionStrings:DefaultConnection": "Data Source=TestSource;Initial Catalog=dbName;Integrated Security=True;MultipleActiveResultSets=True"
}

Migration.exe -connectionString arguments does not work doing EF migration on CI server

I am trying to do database update of code first migration on a build server.
I read about using migration.exe from EF 6 tools, and passing misc. context and connection settings in as arguments to the migrate.exe call.
I want to be able to specify the connection string, default catalog and security myself directly as arguments.
The problem is that when I have specified my connection string, etc. like:
migrate.exe Ef.Data.DLL /ConnectionString:"Data Source=myserver;Initial Catalog=MyCatalog;Integrated Security=true" /connectionProviderName:System.Data.SqlClient /verbose
Then migrate.exe will throw an error:
System.InvalidOperationException: No connection string named 'MyContext' could be found in the application config file
My context is defined in code like:
public MyContext(): base("name=MyContext")
So it expects a MyContext connection string like it was still trying to use an App.Config or web.config for this, but it should not, since I'm passing this information in as arguments.
If I try to specify a ConnectionStringName as argument (-connectionStringName:MyContext) along the other args. the I get:
ERROR: Only one of /connectionStringName or /connectionString can be specified.
So I'm pretty stuck here. Cant seem to solve this one. Any ideas are highly appreciated.
I had the same issue today. For me, it was sorted by changing my context constructor, from this:
public RootContext() : base("name=MyContext")
to this:
public RootContext() : this("MyContext")
Having the name= in front of the context name forces the value to be found in the config otherwise it throws an error. This is great when you're only deploying from Visual Studio because it'll helpfully throw errors if your strings don't match, but not so great when trying to automate migrations in different environments from the command line.
So, if you make this change, be careful when running your migrations in VS - if your strings don't match it'll happily continue and create a new database in LocalDB named "MyContext" without telling you that's what it did!

EF Code first migrations not running after deploy to Azure

I have two folders for my migrations (AuthContext and UserProfileContext), each has their own migration and some custom sql to run afterwards for data migrations and whatnot.
This works fine when using package manager console. I
Restore from production
Run Update-Database -ConfigurationTypeName Migrations.Auth.Configuration
Run Update-Database -ConfigurationTypeName Migrations.UserProfile.Configuration
Then everything is very happy in the new database, migrations executed data shuffled where it needs to.
I tried to test out the migrations on publish piece by:
Restore production on dev database
Single connection string (all contexts use the same) pointed to dev database
Publish to azure web site
Checked the box for Apply Code First Migrations
Selected that single connection string
Okay it published fine; however, when I went to look at the database, nothing happened! It did not create the necessary tables, columns, or data moves.
TLDR; Code first migrations are not running after publish to Azure
Update 1
I've tried any combination of the below: only one single connection string so I'm guessing that's not the issue, and execute migrations is checked.
On publish the api runs but no database changes are made. I thought perhaps I needed to hit it first but I just get random errors when I try to use the api (which now of course relies on the new database setup), and the database is still not changed.
I've seen a couple references out there about needing to add something to my Startup class but I'm not sure how to proceed.
Update 2
I solved one issue by added "Persist Security Info=True" to my connection string. Now it actually connects to the database and calls my API; however, no migrations are running.
I attached debugger to Azure dev environment and stepped through... on my first database call it steps into the Configuration class for the Migration in question, then barfs and I can't track down the error.
public Configuration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\Auth";
ContextKey = "AuthContext";
}
Update 3
Okay, dug down and the first time it hits the database we're erroring. Yes this makes sense since the model has changed, but I have migrations in place, enabled, and checked! Again, it works fine when running "Update-Database" from package manager console, but not when using Execute Code First Migrations during publish to Azure
The model backing the 'AuthContext' context has changed since the
database was created. Consider using Code First Migrations to update
the database (http://go.microsoft.com/fwlink/?LinkId=238269).
Update 4
Okay I found the root issue here. VS is setting up the additional web.config attrib for databaseInitializer on only one of my database contexts, the one not mentioned is in fact hit first from my app.
So now I have to figure out how to get it to include multiple contexts, or, combine all of my stuff into a single context.
The answer to this post is not very detailed.
This article explains what I had to do to fix a similar problem to this:
https://blogs.msdn.microsoft.com/webdev/2014/04/08/ef-code-first-migrations-deployment-to-an-azure-cloud-service/
I'll roughly describe the steps I had to take below:
Step 1
Add your connection strings to your dbContexts, in my situation, they were both the same.
Step 2
Add this to your web.config
<appSettings>
<add key="MigrateDatabaseToLatestVersion" value="true"/>
</appSettings>
Step 3
And add this to the bottom of your global.asax.cs / Startup.cs(OWIN startup)
var configuration = new Migrations.Configuration();
var migrator = new DbMigrator(configuration);
migrator.Update();
Solved! To summarize the solution for posterity:
Enable Code First Migrations only enables them for one base connection string per checkbox checked, regardless of how many contexts have migrations against that base connection string. So in my case I broke out the two in question into two different connection strings.
Then I was hitting other errors and identified that if you're changing the base connection string to the model backing asp identity you need to include (one time publish) the additional flag base("AuthContext" , throwIfV1Schema: false)
For anyone who has this issue and may have overlooked the following: be sure to check that you have correctly set the connection string in your Web.config file and/or Application settings on Azure. This includes DefaultConnection and DefaultConnection_DatabasePublish.
In our case the former was correct but the latter contained the wrong database instance because it had been carried over from an App Service clone operation. Therefore the wrong database was being migrated.

How to handle EF code-first migrations from my local machine when deploying to Azure?

I finally figured out how to get web.config transformations working, so that locally I have one connection (the one in my default web.config), and then when I publish to Azure, the "debug" transformation is applied so that an Azure-SQL database connection string is used.
That much is working, but now I'm running into a problem with database migrations.
In my Configuration:
protected override void Seed(MG.Context.MentorContext context)
{
System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<MentorContext, Configuration>());
if (!WebSecurity.Initialized)
WebSecurity.InitializeDatabaseConnection("DefaultConnection",
"User", "UserId", "Username", autoCreateTables: true);
}
Now, when I'm running locally and want to update my local database, I open up Package Manager Console and type in 'update-database' and everything works wonderfully.
Sometimes I want to update the remote Azure-SQL database though - so in the past I've done this:
Update-Database -ConnectionString "azure connection string here" -verbose
which was working when I was manually updating my local web.config. Now that I'm using the above transformations, even though I specify a connectionString, DefaultConnection in my Seed method resolves to the un-transformed connection string (my local db), so the Membership tables never get created on the Azure database.
This can be solved by manually updating the default web.config, but that defeats the purpose of using these transformations.
How can I have these transformations applied so that the Seed method of my EF migrations uses the Azure connection strings - OR - how can I tell update-database to use the azure connection string?
I'm trying to avoid manually swapping the connection strings if I can.
You mention a Web.config and "publishing" to Azure; are you using Azure Web Sites?
If so, look at this article. In short, if you configure a connection string on the K/V store of Azure Web Sites with the same name as your connection string, the value you set on Azure will automatically take precedence:
Connection strings work in a similar fashion, with a small additional
requirement. Remember from earlier that there is a connection string
called “example-config_db” that has been associated with the website.
If the website’s web.config file references the same connection string
in the configuration section, then Windows Azure
Web Sites will automatically update the connection string at runtime
using the value shown in the portal.
This should ensure that you Seed method attempts to connect to the right database.

Database Connection Error with ef-code-first

I'm new to ef code first and have just used the reverse engineer code first to create a model of an existing database on Microsoft SQL Server 2008.
The problem I'm having is that even though I'm providing User ID and Password in the connection string, it's giving me an authentication error while complaining about my computer name as if I were using Integrated Security (which I'm not.)
The error I get is this:
Cannot open database \"edmTestDBContext\" requested by the login. The login failed.\r\nLogin failed for user 'jwelty-thinkpad\jwelty'.
My connectionString is this:
Data Source=srv-123;Initial Catalog=edmTestDB;Persist Security Info=True;User ID=user;Password=userpass;MultipleActiveResultSets=True
It seams to me like it's ignoring my User ID and using my machine name instead.
It's interesting that the connection string was auto generated by the Entity Framework tool and it worked for building the model but not for actually connecting the model back to the source database.
Any thoughts on what's going on?
I do have full permissions with my username/password as this is what I use with Sql Server Management Studio and that's also how I created the database in the first place.
I tried adding "Integrated Security=False;" and that was no help.
It looks like EF isn't finding your connection string. Make sure that it is in the config file being used (you might need to copy it from the class library config to the application config) and that it either has the same name as the context class or that you provide DbContext with the name by calling the appropriate base constructor. For example:
public EdmTestDBContext()
: base("name=MyConnectionStringName")
{
}
There are some built-in conventions in EF Code-first such as using the name of derived context class from DbContext to find the related connection string in the .config file.
So if your context class is named BlogContext, it will look for the following connectionString first:
<connectionStrings>
<clear />
<add
name="BlogContext"
...