EF database migrations - asp.net-mvc

I'm working on an MVC4 application that uses Entity Framework 5, database migrations, and the asp membership api. In my development environment I can delete my database entirely, run a package (.zip), refresh the page and all works as expected; a database gets created, the seed method is called and some default values are stuck into the database.
Perfect, really easy too! But.....yes, there is always a but!
When I go to deploy this same package(only changed the db connection string) and run this in a remote environment, the behavior changes. Again, if I go in and delete the database entirely, run the package (.zip), refresh the page, the database gets created with only the asp membership api tables. I've checked the connection string, and that is for sure, not the cause, or else the database and membership tables couldn't get created.
I am aware of using the nuget package manager, which is really a powershell instance, but I am not using it since it cannot be used in the production environment. I'd like the package to handle it all, and in my test environment, it works perfectly.
Does anyone have any suggestions? Could this be a side effect of mixed migration history?
Thanks in advance!

The default MVC4 Internet Application project messes up a lot of people. Microsoft wanted to demonstrate the SimpleMembership functionality, which requires an EF context, but it's not common sense that you have to actually modify this portion to effectively use the rest of your app.
So, a little primer on how Entity Framework works will help clear up why this happening I think.
Entity Framework (at least version 5, it may change in 6 or successive versions) only allows one DbContext for your application. Most likely, you have at least two, the AccountsContext that was autogenerated by the project template and the context you use for the rest of your application. If you were to turn off automatic migrations and attempted to generate a migration, EF would helpfully tell you that you need to specify which context to use. However, automatic migrations are the default in Code First, very few disable that, and thus very few ever get alerted.
When automatic migrations are enabled, and you have no existing database, EF happily (and silently) creates the database for you from your context. But, what if you have multiple contexts? Well, the other nasty little feature of EF is that it creates the database just-in-time. So, which context gets used is a function of which one is accessed first. Nice, huh? So, if you attempt to do anything like a logon, then the database is created from the AccountsContext and then, when you try to access something from your app's context, the database already exists, and EF does nothing.
So, what to do about this? Well, you need one context to remove ambiguity. You can still have more than one context if you want in your app, but you have to essentially tell EF that all the other contexts are database-first, i.e. don't do anything.
public class AccountsContext : DbContext
{
public AccountsContext()
: base("name=YourConnectionStringName")
{
Database.SetInitializer<AccountsContext>(null);
}
...
}
public class MyAppContext : DbContext
{
public MyAppContext()
: base("name=YourConnectionStringName")
{
}
// All your entities here, including stuff from AccountsContext
}
MyAppContext will be your "master" context, which will have every entity in your database that EF should know about. The base call on both serves to take EF's guessing out of of the way and explicitly make sure everyone is one the same page as to what database connection should be used. Your AccountsContext is now essentially database-first, so it won't spark EF to create the database or attempt any migrations -- that's what MyAppContext is for. You can create other contexts in the same way as AccountsContext to break up your app's functionality; you just have to mirror any DbSet property declarations into your "master" context.
Julie Lehrman calls this concept "bounded contexts" in her book, Programming Entity Framework: DbContext, and presents a generic class you can inherit all of your "bounded contexts" from, so you don't have to specify the connection string name and set the database initializer to null each time.

Related

Entity Framework 7 and ASP MVC 5 - simple tasks

I am sorry if I am asking something that has an obvious answer, but I have spent and entire day searching for resources on the subject and I fail to find or understand how to do a few basic thing with EF7.
So, here is my question.
I have an ASP MVC 5 (VNEXT) website and I am using Entity Framework 7. I have an existing database, thus I am working database-first.
So far everything was fine. I installed everything required to get my DNX EF commands up and working; I scaffolded a dbContext and I got all my tables as classes and a dbContext class.
Everything fine, all well. I was happy and continuing with my work.
However, I got to a point where I wanted to make a property of one of the generated (table) classes Required, because I use jQuery unobtrusive validation.
I have the following resource as a reference: http://ef.readthedocs.org/en/latest/modeling/required-optional.html
My first wonder is, according to this source, in the FluentAPI the property has been marked as .IsRequired(). I believe, making it required here is a whole other thing that has nothing to do with unobtrusive validation. So, the next thing explained is simply - go to your class and add the Required data annotation.
This is all fine and well, and after adding it, it works as it should.
But I immediately wondered - well, I am modifying the generated classes, am I not going to lose those changes once I update the model?
Which leads me to my final problem - I searched for a long time, I even played with the help menu of DNX EF, but I am unable to find the right way to update the dbContext and generated models after I make changes to the database.
I believed this to be something quite trivial but to my surprise I am unable to find a resource explaining how to do the update.
Can you point me in the right direction, and tell me how to update EF generated models and context after I make changes in the database schema, and what is the best way to add annotations to the properties of the generated classes?
The general consensus is that you shouldn't use your database entities as input from users directly. Instead, use ViewModels, verify those against your validation rules, then map them to database transactions.
As asp.net MVC developer I use database first and updating database is a big head ache so I use Metadata approach and create ViewModels which helps allot.

Model compatibility error

Setup
I have an app that uses ASP.NET Identity 2.0. The identity part shares a database with the rest of the tables needed by the application. So in one class library, I have a dbcontext that accesses the database for business data, and in another class library, I have the IdentityModel.cs, ie, the ApplicationDBContext.
Problem:
All worked fine, until I got in a muddle, trying to figure out how to work with migrations with the business data context. I ended up deleting the __MigrationHistory table and hence all the model metadata in the database for both the context.
I now get the following error:
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.
I deleted all migrations related to the business data, and re enabled migrations for that project. That had the effect of recreating the model metadata for the business dbcontext.
However, I can't figure out how to achieve the same for the Identity metadata.
Question:
How do I recreate the model metadata in __MigrationHistory for ASP.NET Identity 2.0?
Write below code in Global.asax.cs and try again...
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<TsContext>());
I had to recreate the database and start again. I am still in the dark to the extent that I don't know if Neel's answer is the correct one for a production database. Right now, I don't have the time to properly research AspNet.Identity to find the solution to the problem. Sorry.
Prevention before Cure:
What I DO know is that the problem would not happen if I hadn't deleted the __MigrationHistory table. So the issue is one of self harming and so prevention rather than curing is the best option.
Therefore, the moral of the story is:
Moral:
Never, EVER, delete the __MigrationHistory table. Learn a bit more about it BEFORE doing any thing quite so silly, feckless, carless and downright dumb.

MVC 4 + Entity Framework 5 + Stored Procedures

I'm just now teaching myself MVC4 (did webform for years), and I'm
frustrated - but not about MVC which is pretty good. Entity Framework
is...well
I'm using VS2010.
The problem
We have a real database, you know normalized with like foreign keys and stuff. But every example I find for Entity Framework is direct to the table, but we rarely have a straight table pull - out side of populating dropdowns and such. All of our frontend calls hit a Stored Proc (how old school! expletive deleted)
I love the Model architecture of MVC where you define the attributes of the data coming from the data source - Display Name, Ranges, DataType. etc. So I definitely want to keep this.
Entity Framework and MVC do not want to play well in this senario. I created my edmx file (with SPs only), did my function import for a SP, everything is good....'til now.
Can't Create a Controller from the edmx/designer - Enter Controller Name, pick MVC controller with read using EF, pick the model class that is the FuntionName_Result, and for context pick the ...Entities name. FAIL Unable to retrieve metadata
OK, so now I try EF 5.x DbContext Generator, update the file name and boom I have a model and context - awesome now I can do the cool MVC stuff, lets rebuild the site....oh the horror - everything has been previously defined.
I tried generating the edmx in a different folder and/or deleting it after the DBContext generator, still can't create Controller.
'blah' is not part of the specified 'Context' class, and the 'Context' class could not be modifed to add a 'DbSet' property to it. (For example, the 'Context' class might be in a compiled assembly.)
IF I manually add the DBSet, I'm back to unable to retreive metadata - I am assuming this is happening because it can't connect to the DB. I don't know where to tell it to use the connection string in web.config. - if this is the problem
Here lies dead my MVC hopes of a brighter future.
What am I missing?
I am not married to EF, so if there is a better way to access databases (without writing all the code from scratch) I'm here to listen.
Thanks
Entity framework relies heavily on conventions. It takes a little bit to get used to. For example for connection strings... If entity framework doesn't find a connection string with the same name as your DBcontext class it just makes one (i think it defaults to using the project name as the database name). If this database doesn't exist it will create it locally as a sql express DB. This leads to the kinds of errors like the ones you are reporting.
If you want to define the connection string for entity framework all you need to do is provide a connection string in the web.config. Again conventions.... the connection string should be named the same as your DBContext class and entity framework will just find it.
<connectionStrings>
<add name="MyDbContextClassName" connectionString="..." />
</connectionStrings>
On an architecture note, IMHO ORM's are defiantly the way to go for new application development. It makes getting data into and out of your database soo much easier. That said it is a Big paradigm shift if you are used to accessing everything via sprocs and direct queries to the DB. Don't give up on it. It will frustrate you at first just like picking up any new tech, but it's well worth it in the end.
I have used entity framework and nHibernate for ORM in the past. The thing that I like about entity framework is that if you use code first migration most of the really annoying, tedious, and error prone column mappings are auto generated for you (again using conventions). You sometimes still end up having to do a little mapping but those cases are pretty rare. Maybe a little less rare if you already have a database since your column names will probably not always match entity frameworks conventions. Anyway... This is a big plus in my book and why I would defiantly favor EF over nHibernate.
If you already have a database, with stored procedures you do not need the EF 5.X DbContext Generator. Create either a folder in your project or a new project in your solution for your data access. In that folder/project add a edmx file and configure it to an existing database using the wizard. At this stage you can pull in your stored procedures.
If you open the edmx file, you can go to the model explorer tab and manage the imported functions (stored procs) and their return types.
Once you have that, In your controller, rather than using an instance of DbContext you can just use an instance of your EF Entities. So if you called your edmx 'MyDbAccess' you should be able to use MyDbAccessEntities which will then allow you to access the stored procedures.
I in your App.config file check your
<connectionStrings>
After check if your stored procedures are added in the model context file
YouDBModel.Context.tt
> YourBDModel.Context.cs

Entity Framework 5 - Code First Production Preparation

As part of our intended migration from Linq2Sql to Entity Framework, we have created a small EF model consisting of ten entities. Because we are working with a legacy application we are using the 'code first' option and manually mapping our POCO objects to tables within the database. We do not want the Entity Framework code to update the database. I believe that the following is all I need to do to achieve this - I would appreciate confirmation as I was not sure whether the SetInitializer code should go here or perhaps in the Global.asax code.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<InboxDataContext>(null);
modelBuilder.Configurations.Add(new Subscribers.Mapping.DataSourceMap());
modelBuilder.Configurations.Add(new Subscribers.Mapping.SubscriberMap());
...
}
As part of this update, we have created a small test page (MVC controller and views) and added it to our main application project. During development and testing this has worked well. The only thing we did notice is that if we updated the underlying EF model, the initial page load seemed to take several minutes to render. I assumed this was because EF had to rebuild its views and mappings to reflect the changes - to my disgrace, I didn't worry too much about this as a) I don't have a full understanding of how this works and b) it only seemed happened on model changes.
This morning we loaded this update to the production server for initial testing and this time the initial load problem became much worse - so much so in fact that the test page never loaded.
So, to get to my questions:
Is there anything else I should/should not be doing to prepare my
application for production?
How can I improve the initial load performance?
How can I find out why the initial load on the production server
never completes - I am not seeing any error messages?
I did try downloading the Entity Framework Power Tools and running the 'Generate Views' option on the derived DbContext class, but since I could only run this in the development environment I was not sure whether this would work when copied to the production server - it didn't appear to.
I should mention that the development environment contains just one hundred records in the main table and the production environment contains almost one million records (same schemas), again I wasn't sure if this would make any difference.
Any help advice would be appreciated.
Thanks.
Firstly, if you are using an existing database then a better approach would be Model First. You can connect your Edmx to your current database and it will gather all the required mappings as they currently stand. It then also generates the POCO classes and DbContext (with EF5, you have to do it manually in <5). Using this approach may cut down on initialisation time as your code wont have to create a model at runtime.
Give this a try, and it might solve all your problems (I believe they are all related).

EF4 and ASP.Net MVC to Test and Develop without mapping to an underlying database (until later)

I want to develop an ASP.Net MVC application with EF4 Model First design and only generate the actual database much later, ideally at the end of the project.
Based on some of the ideas here:
http://elegantcode.com/2009/12/15/entity-framework-ef4-generic-repository-and-unit-of-work-prototype/
I want to create something like an InMemoryObjectContext for testing and development and use IOC to switch to the SQL Server implamentation (EF generated) for UAT and production.
Is this wise?
Is it possible? If so, does anyone have any suggestions?
Does EF always need an underlying database in order to track changes, commit etc?
I've tried creating a model first but as soon as I add properties I get the following errors:
Error 2062: No mapping specified for instances of the EntitySet and AssociationSet in the EntityContainer Model1Container.
and the warning:
Running transformation: Please overwrite the replacement token '$edmxInputFile$' with the actual name of the .edmx file you would like to generate from.
The error doesn't stop the application running but worries me. I'm very very new to EF so I apologize if this is way off the mark or a dumb question. I'm hoping to get some good advice while I sit for the next few days and watch videos and read articles.
Thanks
Davy
At the very least you need mapping information "filled in". You can fill these fields with nonsense if you don't want to work against the underlying database.
If your doing Model first, right click on the designer canvas and select, "Generate Database from Model". This will automatically create convention based mappings for you without defining tables and columns. You don't even need a valid db connection to do this.

Resources