locked
ASP.NET MVC3&4 Code First is not creating tables RRS feed

  • 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".





    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".





    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