4

I just started trying my hands on EF4 code first this morning and I created my POCO, data context and Initializer classes in a separate class library, I believe it's the regular boiler plate type code. I reference the class in an MVC3 application and set the initializer in the Global.asax. On running the app, I notice the following problems
1. No database is created anywhere (Then I add an entry in the web.config for a connection string named after the Context class, still no result)
2. When I try to access the initalized values, I get a null error, obviously because there is no data.

Can anyone please help me with pointers on how to get thi thing to work (would be a shame if I spent my entire christmas day learning this and I still can't get it to work :( ) Thanks
p.s. I tried inserting break points and I hit the app initialization method, but it never hits the Seed method in the initializer even though I add a break point there as well!!
Thanks.
Initializer class

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Entity;
    using F2AController.Models;

    namespace F2AController.DataObjects
    {
        public class F2AInitializer : DropCreateDatabaseAlways<F2AContext>
        {
            protected override void Seed(F2AContext context)
            {
                var countries = new List<Country> 
                {
                    new Country(){ CountryName="Germany", Active = true},
                    new Country(){ CountryName="Britain", Active = true}
                };
                countries.ForEach(s => context.Countries.Add(s));
                context.SaveChanges();
                var providers = new List<Providers>() 
                {
                    new Providers(){ ProviderName="InfoBip", ContactDetails="Rturo Manovic", Active=true, MessageRates= new List<ProviderRates>(){new ProviderRates(){ CountryId=1, DateCreated=DateTime.Now, DateModified=DateTime.Now, Rate=0.05M, Active=true}}}
                };
                providers.ForEach(p => context.Providers.Add(p));
                context.SaveChanges();
                var usermobiles = new List<MobileTerminal>()
                {
                    new MobileTerminal(){ Active= true, Credits=200, DateCreated=DateTime.Now, MSISDN="4477565444865"}
                };
                usermobiles.ForEach(u => context.MobileTerminals.Add(u));

                context.SaveChanges();
            }


        }
    }

Context Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;

namespace F2AController.Models
{
    public class F2AContext : DbContext
    {
        public DbSet<Country> Countries;
        public DbSet<MobileTerminal> MobileTerminals;
        public DbSet<Providers> Providers;
        public DbSet<ProviderRates> ProviderRates;
        public DbSet<Property> Properties;
        public DbSet<ShortMessage> ShortMessages;
        public DbSet<UserProperties> UserProperties;

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }
}

Global.asax App initialization method

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        Database.DefaultConnectionFactory = new SqlConnectionFactory(ConfigurationManager.ConnectionStrings["F2AContext"].ConnectionString);
        Database.SetInitializer<F2AContext>(new F2AInitializer());

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }
Obi
  • 3,091
  • 4
  • 34
  • 56

3 Answers3

4

Eureka..finally!
While searching for a solution, I came across this post Entity Framework Database.SetInitializer simply not working
Applying the solution suggested there to force my database to create worked at start up like I expected, but then while running the seed code, it threw a null pointer exception. While investigating, I realized that any attempt to reference the DBSet collections from the Context class yielded the same exception. Inspecting further I realised that instead of using

 public DbSet<MobileTerminal> MobileTerminals { get; set; }

I had used

   public DbSet<MobileTerminal> MobileTerminals;

Which meant that I did not get any implicit object initialization, hence the null pointer exception. I removed the forced initialization code and ran the app again, this time the seed code didn't run until I accessed a page which actually queried the data context and it ran perfectly.
Apparently, due to Lazy loading, the initialization code is not run until it is actually needed, i.e. the first time the data context is queried in the application.

I hope this helps anyone who has the same problem in the future.

Community
  • 1
  • 1
Obi
  • 3,091
  • 4
  • 34
  • 56
  • Slightly off-topic, but a fun one to debug is using the above code with `DropCreateDatabaseIfModelChanges` instead of `DropCreateDatabaseAlways` (*face-palm* moment). If you came to this page for this issue and the above solution doesn't work, check that you didn't do this. A quick work around is to change it to `DropCreateDatabaseAlways`, or just add a dummy property to your model/remove the dummy property. – Aaron Newton Aug 24 '12 at 00:52
1

I wanted to share another issue when using a class library for code first & stumbled across this post. I had my code first POCO and DataContext classes in a library project too and wanted to use this project to create my code first database. I figured out that there is a -ProjectName flag with which one can specify the class library project to look for when creating the database.

   add-migration -Name 'InitialCreate' -ProjectName 'MyProject.Data'

   update-database -ProjectName 'MyProject.Data'  
tribal
  • 219
  • 3
  • 14
  • In the Package Manager Console `get-help enable-migrations -detailed` or `get-help add-migration -detail` to see other helpful flags for the situation where DBContext and Entities are in a class library but the connection string is in another project – subsci Aug 15 '14 at 21:40
0

The issue might be with the connectionstring you are using in your web.config.

For SQL CE use following

<add name="YourContext"
  connectionString="Data Source=|DataDirectory|yourDB.sdf"
  providerName="System.Data.SqlServerCe.4.0"/>

For SQL Express use following

<add name="YourContext"
     connectionString="Data source=.\SQLEXPRESS;Integrated Security=True;Initial Catalog=YourDatabase;" 
     providerName="System.Data.SqlClient" />

I guess this should make things work.

Also, I think you should look at this article EF Code First DB Initialization Using Web.Config. It's better to initialize the database from web.config rather than from global.asax file

Pankaj Upadhyay
  • 12,966
  • 24
  • 73
  • 104
  • Hi, thanks for your reponse. I've done that and still no love. I tried checking the connection string being used in the Application_Start method and its a SQl Express connection string with no Initial Catalog set. This is despite the fact that I have set the connection string int he web.config AND in an app.config file in the class library. What are your thoughts? Thanks – Obi Dec 27 '11 at 15:25