JMK
JMK

Reputation: 28059

One Context class, two Model classes

I'm learning MVC, and I understand how to create a single model class, and then a single context class, and then create a controller and a view based on the model/context combination, and commit the model to a database using code-first.

Now I want to bring a second Model (and therefore table) into the mix. I initially tried creating a second context class, and then a second model class, and then a controller and a view in the same way. As a result of this I found out that I could only commit one model to the database at a time. Whenever I enabled automatic migration on one model, and then ran the Update-Database command in the package manager, the other table disappeared from my database, and the add/remove/edit/view functionality for the other model broke.

Surely you must be able to use this techinque to manage more than one table? My question is, if I have two model classes like below:

[Table("TableOne")]
public class ModelOne
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    public string Foo { get; set; }
}

[Table("TableTwo")]
public class ModelTwo
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    public string Bar { get; set; }
}

What does my Context class need to look like if I want to work with both? My idea was to try this:

public class FooBar : DbContext
{
    public FooBar()
        : base("DefaultConnection")
    {

    }

    public DbSet<ModelOne> TableOne { get; set; }
    public DbSet<ModelTwo> TableTwo { get; set; }
}

Then in the Add Controller wizard, I could select MVC controller with read/write actions and views, using Entity Framework from the Template drop-down list, ModelOne from the Model class drop-down list, and FooBar from the Data context class drop-down list for the first model, and the same options only with ModelTwo in the Model class drop-down list for the second model and everything would work as expected, but whenever I try to create the first controller based on model one, I get this error:

There was an error generating FooBar. Try rebuilding your project.

I have tried rebuilding my project, and I get the same error, so obviously I am doing something greater wrong. What am I doing wrong and how do I need to amend my FooBar context class to get things to work, assuming it is my FooBar context class which is wrong?

Upvotes: 1

Views: 2425

Answers (1)

Chris Pratt
Chris Pratt

Reputation: 239290

Generally, you won't have a 1-to-1 between context classes and model classes. All your associated models all go into one context. I generally have one context per area in my app, for instance, but if you aren't using areas, you can still group models logically in a single context.

Where the problem comes in is in having multiple contexts. EF only likes to migrate one context. Without migrations, you can pretty easily get all the context classes to use the same DB by specifying it manually on the context class.

public class MyContext: DbContext
{
    public MyContext()
        : base("name=MyConnectionName")
    {
    }
}

If each context is defined like that, they will all use the same DB the named connection string points to.

As far as getting migrations to play along, Julie Lerman, the author of Programming Entity Framework: DbContext (and pretty much all the relevant EF books out there), has a solution utilizing a generic base class (edit: actually Julie attributes the pattern to Arthur Vickers of the EF team):

public class BaseContext<TContext> : DbContext
where TContext : DbContext
{
    static BaseContext()
    {
        Database.SetInitializer<TContext>(null);
    }
    protected BaseContext()
        : base("name=breakaway")
    {
    }
}

And, then you have each individual context inherit from BaseContext:

public class TripPlanningContext : BaseContext<TripPlanningContext>
public class SalesContext : BaseContext<SalesContext>

The relevant section starts on page 231 of the aforementioned book.

UPDATE

Actually I lied to you. The pattern Julie gives is simply to make it easier to have them all share the same DB. To get past the migrations for only one context issue, you have to cheat and essentially create one big context with everything in it that you then use only for database initialization/migration. For everything else in your code, you would use your other more specific contexts.

Upvotes: 2

Related Questions