Answered by:
ASP.NET MVC3&4 Code First is not creating tables

Question
-
Hi all,
I'm really having a breakdown on this Code First approach. I checked everything 10 times, restarted my project 10 times and it's really getting demotivational...
I created 2 classes with for each a context:
Imports System.Data.Entity Imports System.ComponentModel.DataAnnotations Public Class B <Key()> _ Public Property ID() As Integer <Required(ErrorMessage:="In of uit is vereist")> <Display(Name:="In / uit")> Public Property InOrOut() As String <Required(ErrorMessage:="Hoeveelheid is vereist"), Range(1, 1000000, ErrorMessage:="€ moet groter dan 1 zijn")> <Display(Name:="Hoeveelheid")> Public Property Quantity() As Integer <Range(1, 1000000, ErrorMessage:="ID moet groter dan 1 zijn")> <Display(Name:="Bijhorend M-ID")> Public Property FromID() As Decimal <Display(Name:="Van")> Public Property FromWho() As String <Required(ErrorMessage:="Datum is vereist")> <DataType(DataType.Date)> <Display(Name:="Datum")> Public Property DateOfAction() As Date <Display(Name:="Notitie")> Public Property Note() As String <Display(Name:="Log-ID")> Public Property LogID() As String End Class Public Class BDBContext Inherits DbContext Public Property Bs() As DbSet(Of B) End Class
Imports System.Data.Entity Imports System.ComponentModel.DataAnnotations Public Class Log <Key()> _ Public Property ID() As Integer Public Property Account() As String Public Property BOrMOrWOrLogOrAccount() As String Public Property Action() As String Public Property ActionID() As Integer Public Property Note() As String End Class Public Class LogDBContext Inherits DbContext Public Property Logs() As DbSet(Of Log) End Class
I made Initializers:
Public Class BInitializer Inherits DropCreateDatabaseIfModelChanges(Of BDBContext) Protected Overrides Sub Seed(context As BDBContext) MyBase.Seed(context) Dim Bs = New List(Of B) From { New B With {.ID = "1", .InOrOut = "In", .Quantity = "1", .FromID = "1", .FromWho = "Eén", .DateOfAction = Date.Parse("1111-11-11"), .Note = "Eén 1", .LogID = "1"}, New B With {.ID = "2", .InOrOut = "Out", .Quantity = "2", .FromID = "2", .FromWho = "Twee", .DateOfAction = Date.Parse("2222-22-22"), .Note = "Twee 2", .LogID = "2"}, New B With {.ID = "3", .InOrOut = "In", .Quantity = "3", .FromID = "3", .FromWho = "Drie", .DateOfAction = Date.Parse("3333-33-33"), .Note = "Drie 3", .LogID = "3"}, New B With {.ID = "4", .InOrOut = "Out", .Quantity = "4", .FromID = "4", .FromWho = "Vier", .DateOfAction = Date.Parse("4444-44-44"), .Note = "Vier 4", .LogID = "4"}, New B With {.ID = "5", .InOrOut = "In", .Quantity = "5", .FromID = "5", .FromWho = "Vijf", .DateOfAction = Date.Parse("5555-55-55"), .Note = "Vijf 5", .LogID = "5"}} End Sub End Class Public Class LogInitializer Inherits DropCreateDatabaseIfModelChanges(Of LogDBContext) Protected Overrides Sub Seed(context As LogDBContext) MyBase.Seed(context) Dim Logs = New List(Of Log) From { New Log With {.ID = "1", .Account = "Eén 1", .BOrMOrWOrLogOrAccount = "B", .Action = "Add 1 en 1", .ActionID = "1", .Note = "1x1"}} context.SaveChanges() End Sub End Class
I made my connection strings in web.config:
<add name="BDBContext" connectionString="Data Source=|DataDirectory|Database.sdf" providerName="System.Data.SqlServerCe.4.0"/> <add name="LogDBContext" connectionString="Data Source=|DataDirectory|Database.sdf" providerName="System.Data.SqlServerCe.4.0"/>
I added the initializers to my application start:
System.Data.Entity.Database.SetInitializer(Of BDBContext)(New Diel.Models.BInitializer()) System.Data.Entity.Database.SetInitializer(Of LogDBContext)(New Diel.Models.LogInitializer())
What happens:
The database only gets created when i manually create an item from within my application. For some reason, it never runs my initializers...
Are there maybe any more conventions I'm missing?
Can you only use one Context in your project?
Can you use only one connection string?Thanks for reading this and looking into the code. Thanks for any help at all.
Tuesday, September 18, 2012 12:16 PM
Answers
-
Hi,
It seems expected. First the initializer is triggered when you actually attempt to use the context (at least read or write an entity). So if your homepage doesn't actually do something with a context, no database is created.
Then when you go on a page that display a table, it creates the db.
But then when you go on the other page using another context, it sees the schema changed (as the table you are trying to use is not part of the other context) and it delete/recreate the db according to the current context (that doesn't include the other table that is then lost).
For a start, I would suggest to create a single context with both tables (a context is supposed to represent a single database, not a single table)...
To clarify you are not forced to use a single context though it's likely the standard practice unless you have much more than two tables. If you want a single context for each table, an approach could be an initialization only context with all entities (and make sure to trigger the initialization before uisng the other context).
For now I would recommend to use a single context until you find a real need to switch to a multi context application.
Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
- Edited by Patrice ScribeMVP Tuesday, September 18, 2012 4:50 PM
- Marked as answer by Glenn CondronMicrosoft employee Wednesday, September 19, 2012 3:44 PM
Tuesday, September 18, 2012 4:36 PM
All replies
-
Just found out something weird.
When I start the application to my homepage, it doesn't create anything on my application start.
When I go to B/Index and I check my database, it creates a table named B. When I then go to Log/Index, the application creates the table Log but suddenly my table B is gone.
I'm probably doing something wrong with those 2 Initializers as it seems that they recreate my whole database when they try to initialize one context.- Edited by Wesley Decay Tuesday, September 18, 2012 12:42 PM Extra info
Tuesday, September 18, 2012 12:37 PM -
Hi,
It seems expected. First the initializer is triggered when you actually attempt to use the context (at least read or write an entity). So if your homepage doesn't actually do something with a context, no database is created.
Then when you go on a page that display a table, it creates the db.
But then when you go on the other page using another context, it sees the schema changed (as the table you are trying to use is not part of the other context) and it delete/recreate the db according to the current context (that doesn't include the other table that is then lost).
For a start, I would suggest to create a single context with both tables (a context is supposed to represent a single database, not a single table)...
To clarify you are not forced to use a single context though it's likely the standard practice unless you have much more than two tables. If you want a single context for each table, an approach could be an initialization only context with all entities (and make sure to trigger the initialization before uisng the other context).
For now I would recommend to use a single context until you find a real need to switch to a multi context application.
Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
- Edited by Patrice ScribeMVP Tuesday, September 18, 2012 4:50 PM
- Marked as answer by Glenn CondronMicrosoft employee Wednesday, September 19, 2012 3:44 PM
Tuesday, September 18, 2012 4:36 PM -
Thanks! Going to try that right away.
I didn't know it was one context per table normally.
Tuesday, September 18, 2012 5:28 PM -
Either my clarification attempt is an epic fail or you really meant "I didn't know it was one context per DATABASE normally." ;-)
Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
Tuesday, September 18, 2012 5:33 PM -
Hi Patrice,
I'm sad to say, I really meant it. Everything is working now as it should and my adventure to MVC exploration continues. Only weird thing now is that my seeding doesn't work. I'll have a look at that today.
Thanks all!
Wednesday, September 19, 2012 10:55 AM -
Doesn't matter. The good point is that you understand now that you should have a single context for all your tables (at least to start with).
For the seed part, you just create a list that isn't related in any way to your context. So the context doesn't know anything about this list and its object instances. What you have perhaps seen is something like http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx but note that once the unrelated list is created the code calls :
dinners.ForEach(d=>context.Dinners.Add(d));
so that each object found in the private dinners list can be known by the context (that will then be able to save them).
Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
Wednesday, September 19, 2012 11:22 AM