My understanding is that a context connects to a database via a connection string specified in web.config. When I create new scaffolds it creates new database .mdf files with a new connection string. I am coming from rails active record with one database and one connection string. So why does asp.net do it differently? Why have multiple database files?
Also I changed the connection string for the user model to my default site database called Toolsite to simplify things and put the users in the same db as everything else -
public ApplicationDbContext()
: base("Toolsite")
{
System.Diagnostics.Debug.Write(Database.Connection.ConnectionString);
}
and this caused a Invalid object name 'dbo.AspNetUsers'. exception even though the table AspNetUsers exists in the database "ToolSite". Is there any other part in the server code that needs to change?
The default MVC project scaffold has always been a pet peeve of mine. When you create a new MVC project with auth, you get a user model and an application context to wire it up. That's great, in one respect, because it lets you immediately run the project with no extra configuration. However, they stupidly decided to put the user model and the application context in the same .cs file, so it confuses developers not familiar with the setup into thinking that the two are intrinsically linked.
In reality, MVC applications are designed to have a single context, and you should actually add your models to the existing context created by the scaffold, rather than create a new, separate context. The only reason to have multiple contexts is if you're literally dealing with multiple databases, and then, only really because you're dealing with existing databases in addition to your application-specific database. In other words, you should only have a single context that is tied to migrations and then you may or may not have additional contexts that operate on a database-first basis. Once you understand that, it becomes far less confusing to work with a scaffolded project.
Related
I have created an ASP.NET Core web application using the MVC pattern (by following this tutorial) and connected it to a local database that is now populated with some data. I have two questions, if someone please help me understand and answer them:
1) My default connection string is set to the following:
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-MyAppName;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Is it possible, only by changing the name and path in this connection string, to re-create the exact same database elsewhere with the data that is currently stored in it (for example, as backup)?
I have found the local database here:
C:\Users\my-name\AppData\Local\Microsoft\Microsoft SQL Server Local DB\Instances\MSSQLLocalDB
But when I try to copy the .mdf file to back up the database, I get an error that says the file is open and cannot be copied. What is it open in? How can I simply back the db file up?
2) After creating a custom controller, I noticed that all the provided properties of my Personmodel are used in the auto-generated code; e.g. in my case:
public async Task<IActionResult> Create([Bind("Birthday,ID,Username,EmailAddress")] PersonModel personModel)
I thought this would mean that if we change the code in the model class, we need to search for and effect the changes accordingly, but then I realized if I want to keep using auto-generated code, I have to do all the same steps as when I am generating it for the first time, and then when it asks if I want to replace the old code with new code, I choose yes.
Is there a better way of doing this, because this would overwrite my custom code every time and destroy the data stored in my local database. Particularly, when I store data in its local database, and then I decide to change a column name or add something, this would override everything...
How do I go about this situation?
Question 1
The .mdf and other files associated with the database will be in use by the SQL Server service. If you want to take a backup, use SQL Server Management Studio - right-click the database in the object explorer, select Tasks and then Backup. If you want to use the backup database then you need to restore it - again in the object explorer, right-click the "Databases" folder and select Restore Database and then browse to wherever you created the backup file.
Question 2 (updated 7th Sep)
When you change your model classes, you can use the add-migration command in the console to generate a new migration class containing the code to transform the database from its current structure to the new structure which matches the updated models. If the migration can cause data loss, then backup the database and restore the backup under a different name before running update-database, You can then create a script to transform the data from the backup into the new structure of the updated database.
Scaffolded components are a bit different to Entity Framework migrations. Migrations are truly auto-generated classes, and most of the time you wouldn't need to update (or even look at) the generated code. Think of scaffolded components as being more like a kind of template - it's a way of getting started with the classes, methods, markup etc that you're most likely to need, which is quicker than writing it all from scratch. It's not an alternative to writing code though, the intent is that once you've created the scaffolded code, you'll maintain it manually going forward. There is no way (that I know of) to automatically update scaffolded code to match a new model whilst retaining any edits you've made to it. You have two options
Re-scaffold the code and then apply your edits to it
Update the code manually to match the new model
All you can really do is weigh up the two options and decide which one is the least effort.
I have tried lots of variations of EF migration v6.0.1 (from no database, to empty databases to existing databases) and I have a particular problem with Azure DB instances not being able to correctly be created on first deploy using Octopus deploy.
There are a number of places where this could be going wrong, so I thought I would check some basics of EF Code First migration with you fine people if I may:
If I create a code-first model, and know that the database does not exist in the intended target database server on Azure. With the default of 'CreateDatabaseIfNotExists' approach and with AutomaticMigrations disabled;
If I then call 'migrate.exe' with the assembly containing my DbContext and migration Configuration will I get a new database created with the current state of the model? or will I get a new database with nothing in it? i.e. do I need to explicitly 'add-migration' for the initial state of the model?
I have read in the documentation that the database instance should be created automatically by the migration process, but no one states clearly (at least to me) that this newly created database will be generated with the current model without a formal 'initial state' migration created.
So the question is this: do I need an explicit migration model generated for migrate.exe to work from?
Through whatever means I try, I get a database but the application launches with the unfriendly message "Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations." Remembering that this is the same application library that just created the database in the first place (from scratch) I fail to understand how this has happened!
I did manually delete the target database a few times via SQL Server management studio, is this bad? Have I removed some vital user account that I need to recover?
Migrations and the Database Initializer CreateDatabaseIfNotExists are not the same.
Migrations uses the Database Initializer MigrateDatabaseToLatestVersion, which relies upon a special table in the database _MigrationsHistory.
By contrast, CreateDatabaseIfNotExists is one of the Database Initializers which relies upon the special database table EdmMetadata. It does exactly as it implies: Creates a database with tables matching the current state of the model, i.e. a table for each DbSet<T>, only when the database does not exist.
The specific error you have quoted here, Model compatibility cannot be checked because the database does not contain model metadata., occurs due to the existence of DbSet<T> objects which were added to the code base after the initial database creation, and do not exist in EdmMetadata.
There are 4 basic Database Initializers available, 3 of which are for use when migrations is not being used:
CreateDatabaseIfNotExists
DropCreateDatabaseWhenModelChanges
DropCreateDatabaseAlways
Also note, the 4th Initializer, MigrateDatabaseToLatestVersion, will allow you to use Migrations even if AutomaticMigrations is disabled; AutomaticMigrations serves a diffierent purpose, and does not interact with the Database Initializers directly.
If you intend to use Migrations, you should change the Database Initializer to MigrateDatabaseToLatestVersion and forget about the other 3. If, instead, you intend to not use Migrations, then the choice of Initializer is situational.
CreateDatabaseIfNotExists will be more appropriate when you are certain that your data model is not undergoing active change, and you only intend to be concerned with database creation on a new deployment. This Initializer will elp ensure that you do not have any issues with accidental deletion of a database or live data.
DropCreateDatabaseWhenModelChanges is most appropriate in development, when you are changing the model fairly often, and want to be able to verify these changes to the model. It would not be appropriate for a production server, as changes to the model could inadvertently cause the database to be recreated.
DropCreateDatabaseAlways is only appropriate in testing, where your database is created from scratch every time you run your tests.
Migrations differs from these 3 Database Initializers, in that it never drops the database, it instead uses Data Motion to execute a series of Create Table and Drop Table SQL calls.
You also can use Update-Database -Script -SourceMigration:0 in the Package Manager Console at any time, no matter which Database Initializer you are using, to generate a full SQL script that can be run against a server to recreate the database.
Firstly, many thanks to Claies who helped me get to the bottom of this problem. I have accepted his answer as correct as ultimately it was a combination of his response and a few additional bits of reading that got me to my solution.
In answer to the actual posts question 'Do I need a migration for EF code first when the database does not exist in SQL Azure?' the answer is yes you do if you have disabled automatic migrations. But there is a little more to be aware of:
The Azure aspects of this particular problem are actually irrelevant in my situation. My problem was two-fold:
The migration being generated was out of sync with respect to the target model. What do I mean? I mean, that I was generating the migration script from my local database which itself was not in sync with the local codebase which created a migration that was incorrect. This can be seen by comparing the first few lines of the Model text in the __MigrationHistory. This awareness was helped by referring to this helpful post which explains how it works.
And more embarrassingly (I'm sure we've all done it) is that my octopus deployment of the web site itself (using Octopack) somehow neglected to include the Web.Config file. From what I can tell, this may have occurred after I installed a transform extension to Visual Studio. Within my nuget package I can see that there is a web.config.transform file but not a web.config. Basically this meant that when the application started up, it had no configuration file to turn to, no connections string at all. But this resulted in the slightly misleading error
Model compatibility cannot be checked because the database does not
contain model metadata.
Whereas what it should have said was, there isn't a connection string you idiot.
Hopefully this helps people understand the process a little better after reading Claies answer and also that blog-post. First though, check you have a web.config file and that it has a connection string in it...
I have set up a solution which contains a number of projects, including one for my models and one for the database contexts (and associated migrations). I have two contexts - one for my standard database (ContextA) and one for the ASP.NET Identity tables (ContextB). (I couldn't work out how to get these to "merge" into my existing context, but they do both point to the same DB).
Every single time I rebuild any project in my solution, I get the error "model backing the 'ContextA' context has changed since the database was created", and I have to do an update-database for EITHER context in order to continue.
I have found that I don't need to do an add-migration at all (and doing so for either context results in empty Up() and Down() methods).
Can anyone tell me what would be triggering the context to thing the model has changed?
Should I consider just adding Update-Database to the build script?
The migrationhistory table in your database is usually associated with one context which then compares against your models to keep everything in sync. I can see why you get this odd behavior. I have two contexts per application instance but I also have two databases.
I recommend you merge your context and models or split them into different databases (which ever makes sense in your app design). This will resolve your issue.
I am very new to entity framework and I am trying to do something like following scenario.
I am creating ASP.net web from application. That website needs to connect to two databases which the schemas are completely different.
I have no idea how the basic structure should be.
I though of have EF on class library. please guide me with instructions since I have less knowledge.
Since you are using two different databases, the only viable option is to create two separate conceptual models. Even if you would be able to merge two different databases into a single conceptual model, it would be a pain to maintain is the databases are of mentionable sizes.
The two models could reside within the same project, in seprate folders to get different namespaces.
E.g.:
Company.MyApp.DataModel
Company.MyApp.DataModel.Model1
Company.MyApp.DataModel.Model2
Then you could put a new layer on top of these two models which do all the heavy lifting, and could even make them look like one database if you want that, or merge data from entities in both models into a DTO or something similar.
Check out the Repository pattern.
If you think about it, when you create a EDM model with Visual Studio it ask you to give an existing database, and when finished creating the model, it generates an EF connection string, that internally address to the given underlying database connection string.
E.g: metadata=res:///EFTestModel.csdl|res:///EFTestModel.ssdl|res:///EFTestModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.\;Initial Catalog=EFTest;Integrated Security=True;MultipleActiveResultSets=True"*
So each model matches only a database, only a connection string.
EF4 still does not support creating one conceptual model which works with N storage models. At least this is not supported with any built-in provider. Perhaps in the future this could be done through a new provider that combines the support of many storages (from the same providers or different).
I havent done enough research on it, but perhaps Windows Server AppFabric (Codename Velocity) could be the bridge to go through this gap.
Note: I have tried even editing manually the xml for the EDM (edmx) to insert a second element inside the tag but it does not match the EDM XML Schema so VS warns about it: Error 10021: Duplicated Schema element encountered.
You are going to use model first approach as the database already exists.
You will need to create two edmx for the two database.
You can create one model project which you can have connection strings for both the edmx in the app.config file and then create your edmx.
I created a login system for one MVC App based on the new Identity framework, and since I already went through all the hard work of modifying my database to match the Identity 2.0 requirements, I was wondering if it would be possible to use it outside of MVC, so I could reuse what I already created, like a login system for a desktop project that I'm working on for example. If so, can I implement the login system on a .dll that can be reused on other projects?
Yes, you could use your existing database for another application. Add the ADO.NET Entity Data Model, and point it to your database. Then, if you need to, select "Update Model from Database" and you should be all set.
Although, it may be just as easy to create your own user/roles tables. It's frustrating (to me) that Identity creates the Primary keys as strings, even though they are essentially Guids.