none
CTP4 w/MVC: where to put SetInitializer?

    Question

  • I am attempting to add Entity Frameword, code first, to an MVC application that's been running with test data, using the CTP4 preview.

    I am currently getting this error:

    The model backing the 'SchedulerContext' context has changed since the database was created.  Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance.  For example, the RecreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.

    I do not want to generate a database at all, as I already have a database. So I tried adding the following to the SchedulerContext constructor:

    Database.SetInitializer<SchedulerContext>(new CreateDatabaseOnlyIfNotExists<SchedulerContext>());

    which had no effect at all -- I got the same error the next time it ran. The error seems to occur when it is executing a LINQ statement that accesses the database -- the first, I think.

    Where should I put this statement, or is this statement the answer to this problem at all?


    CynthiaD
    Thursday, September 09, 2010 12:14 AM

Answers

  • Cynthia, you need to add this code in thei Application_Start section of your Global.asax.cs file which is in the root of  your website.

    protected void Application_Start()
    {
      Database.SetInitializer<MNG_Model>(new RecreateDatabaseIfModelChanges<MNG_Model>());
    
      //or you can create a class based on AlwaysRecreateDatabase<MNG_Model> 
      //Database.SetInitializer<MNG_Model>(new MNGInitializer());
    }
    

    Here is an example of a class base on Always....

     public class MNGInitializer: AlwaysRecreateDatabase<MNG_Model> 
     {
      protected override void Seed(MNG_Model db)
      {
       this.BuildWebAccounts(db);
       this.BuildFriends(db);
       this.BuildProducts(db);
      }
      private void BuildWebAccounts(MNG_Model db)
      {
       WebAcct wa = new WebAcct();
       wa.UserName = "Terrence"; //1
       db.WebAccts.Add(wa);
    
       wa = new WebAcct();
       wa.UserName = "David"; //2
       db.WebAccts.Add(wa);
    
       wa = new WebAcct();
       wa.UserName = "Holly"; //3
       db.WebAccts.Add(wa);
    
    
       db.SaveChanges();
      }
      private void BuildFriends(MNG_Model db)
      {
    
       Friend fr = new Friend();
       fr.WebAcctID = 2;
       fr.FriendID = 1;
       db.Friends.Add(fr);
    
       fr = new Friend();
       fr.WebAcctID = 1;
       fr.FriendID = 3;
       db.Friends.Add(fr);
    
       fr = new Friend();
       fr.WebAcctID = 3;
       fr.FriendID = 1;
       db.Friends.Add(fr);
    
      }
      private void BuildProducts(MNG_Model db)
      {
       Product p = new Product();
       p.WebAcctID = 1;
       p.ShortDescription = "Computer1";
       p.LastUpdate = p.DateCreated;
       db.Products.Add(p);
    
       p = new Product();
       p.WebAcctID = 1;
       p.ShortDescription = "Computer2";
       p.LastUpdate = p.DateCreated;
       db.Products.Add(p);
    
       db.SaveChanges();
      }
     }
    
    

     

    Check out page 23 of Scott Gu's blog post on this

    http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

    Hope this helps.

    • Marked as answer by cedubose Thursday, September 09, 2010 8:58 PM
    Thursday, September 09, 2010 1:38 AM

All replies

  • Cynthia, you need to add this code in thei Application_Start section of your Global.asax.cs file which is in the root of  your website.

    protected void Application_Start()
    {
      Database.SetInitializer<MNG_Model>(new RecreateDatabaseIfModelChanges<MNG_Model>());
    
      //or you can create a class based on AlwaysRecreateDatabase<MNG_Model> 
      //Database.SetInitializer<MNG_Model>(new MNGInitializer());
    }
    

    Here is an example of a class base on Always....

     public class MNGInitializer: AlwaysRecreateDatabase<MNG_Model> 
     {
      protected override void Seed(MNG_Model db)
      {
       this.BuildWebAccounts(db);
       this.BuildFriends(db);
       this.BuildProducts(db);
      }
      private void BuildWebAccounts(MNG_Model db)
      {
       WebAcct wa = new WebAcct();
       wa.UserName = "Terrence"; //1
       db.WebAccts.Add(wa);
    
       wa = new WebAcct();
       wa.UserName = "David"; //2
       db.WebAccts.Add(wa);
    
       wa = new WebAcct();
       wa.UserName = "Holly"; //3
       db.WebAccts.Add(wa);
    
    
       db.SaveChanges();
      }
      private void BuildFriends(MNG_Model db)
      {
    
       Friend fr = new Friend();
       fr.WebAcctID = 2;
       fr.FriendID = 1;
       db.Friends.Add(fr);
    
       fr = new Friend();
       fr.WebAcctID = 1;
       fr.FriendID = 3;
       db.Friends.Add(fr);
    
       fr = new Friend();
       fr.WebAcctID = 3;
       fr.FriendID = 1;
       db.Friends.Add(fr);
    
      }
      private void BuildProducts(MNG_Model db)
      {
       Product p = new Product();
       p.WebAcctID = 1;
       p.ShortDescription = "Computer1";
       p.LastUpdate = p.DateCreated;
       db.Products.Add(p);
    
       p = new Product();
       p.WebAcctID = 1;
       p.ShortDescription = "Computer2";
       p.LastUpdate = p.DateCreated;
       db.Products.Add(p);
    
       db.SaveChanges();
      }
     }
    
    

     

    Check out page 23 of Scott Gu's blog post on this

    http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

    Hope this helps.

    • Marked as answer by cedubose Thursday, September 09, 2010 8:58 PM
    Thursday, September 09, 2010 1:38 AM
  • I did add the following line to Application_Start:

    Database.SetInitializer<SchedulerContext>(new CreateDatabaseOnlyIfNotExists<SchedulerContext>());

    But it is still getting the error.

    Does this really mean that my model is not matching my database? Does that mean that EF actually goes out and looks at the database schema, and tries to match it up with the model? Or is it just reacting to the fact that I made some changes to a couple of properties in my POCO classes?


    CynthiaD
    Thursday, September 09, 2010 3:57 PM
  • If you have changed your poco classes, then your model is different than the current version of your db.  It puts a table in your model that has a hash of the schema, so when you change something in your model it checks the model against that hash and if it is different, it rebuilds it.

    Is the reason you don't want to regenerate a new database is because you have good data in the current database?  If so, you will need to synch up your model to match the database, or make changes to you db to match your new model.

    Thursday, September 09, 2010 4:04 PM
  • Well, the changes I made to the POCO classes should have made it match the database BETTER: I changed a couple of enums (that I had forgotten about) to strings.

    One of the reasons I wanted to create a database first is, I am using several Views that aggregate data from other databases. I understood that you could not access tables from multiple databases in EF, so that was my solution to that: to add Views that accessed the outside data. Obviously, these tables are read-only.

    OK: I tried changing the name of the context class and changed the connection string to a SQL Express instance, and changed the SetInitializer to use "AlwaysRecreateDatabase", just to see what kind of a database it would create.

    As I expected, it creates Tables where I wanted Views, so I really can't use this feature.

    The other tables seem exactly the same as my model, with one big exception: it added new tables for each of my lookup tables. I have three lookup tables that connect two tables together: DateEvents, SiteEvents, and InterviewEvents. I included those in my model.

    Now EF comes out with DateEvents, SiteEvents, and InterviewEvents, just like in my model, but it has added four new tables: dateEvents_flaggedDates, events_flaggedDates, events_siteEvents, and interviewEvents_interviews, which seem to be related in some way to relationships defined by these lookup tables.

    I think possibly I should not have navigation properties on these lookup table classes ... ? Maybe it is confusing EF.


    CynthiaD
    Thursday, September 09, 2010 5:19 PM
  • Cynthia, it looks like we are morphing into another topic, how your model translates into the db, so let's close out this thread, and if I answered your original question about Where to put SetInitializer, then mark my answer as "mark as answer".

    Then start another question and I will be glad to pick up the conversation over on that thread.  I may be able to help a little, but I am pretty new at this code first stuff also.  A new question will bring more people who have better knowledge into the conversation.

    I would post your model in the other question so we can see what you are doing. Maybe it is as simple as removing the nav properties.  I can't help on the cross db and view issue, but I bet you are right about little support in EF with this at this point, but who knows, maybe Mr. Miller will jump in.

    Terrence

    Thursday, September 09, 2010 6:35 PM
  • I have started a new thread here: http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/a3d7e3b0-936f-44e7-88f9-3c36ccd2f53a

    Thanks for your help so far!


    CynthiaD
    Thursday, September 09, 2010 9:42 PM
  • Hi Cynthia,

    This is a bug in CTP4, in future releases you won't have to write any additional code if you are mapping to an existing database that was not generated by Code First.

    In CTP4 you want to switch off the database initializer by setting it to null; Database.SetInitializer<SchedulerContext>(null);

    ~Rowan

    Monday, September 13, 2010 11:56 PM