MvcScaffolding Joy Ride with EF Code First

Okay, so here’s the situation: you are creating a web-based application that contains a series of tables, one of which has multiple one-to-one relationships with another table.

In your view, you’ll obviously have a series of drop downs that let you pick entities from the second table. This ensures data integrity, but is a bit of a PITA to wire up.

How do we put it all together?

A Quick Overview

All this work is really not that bad with the latest tools refresh, and only takes a few lines of code.  Let’s get there step by step and see how to make it happen.  I’m going to make a Movie entity and a FavoriteMovieProfile entity.  Here’s how she goes:

  1. Create a new ASP.NET MVC3 Internet Application.
  2. Use NuGet to install MvcScaffolding.
  3. Create a Movie class. POCO here, nothing special.
  4. Create a FavoriteMovieProfile class, with a bit of EF flavor.
  5. Scaffold our controllers with the repository pattern from the Package Manager Console.
  6. Extend the MoviesContext and create our own initializer for the database.
  7. Rescaffold the controllers.

Let’s Get Started – Project Setup

Okay, fire up Visual Studio 2010 and make sure you have the latest bits. Create a new project and select the type ASP.NET MVC 3 Web Application. I named my project Movies.Web and called the solution Movies.

image

Create an Internet application, Razor view engine and HTML5, because that’s the in thing to do.

image

Go to the Package Manager Console and type the following:

Install-Package MvcScaffolding

This goes out to the interwebs and grabs the latest version of this toolkit, along with the required bits to generate the scaffolding.  Going about its business, the Package Manager copies the packages to your project directory, updates your packages.config file and executes the required integration steps to light up the new references in your project.

Sweet.

Creating the Classes

Okay, right click on your Models folder and create a new class called Schema. When the file opens, delete the class definition (I just want the file named schema). Add the following using statement at the top of the file:

using System.ComponentModel.DataAnnotations

We’re going to add two classes to the namespace, the first is Movie:

public class Movie
{     
public int MovieID { get; set; }     
public string Title { get; set; }     
public string LeadActor { get; set; }     
public string Director { get; set; }
}

Next, add in the FavoriteMovieProfile class like so:

public class FavoriteMovieProfile 
{    
 public int FavoriteMovieProfileID { get; set; }     
public string Name { get; set; }     
public int ComedyID { get; set; }     
public int HorrorID { get; set; }     
public int DramaID { get; set; }     
public int SciFiID { get; set; }     
public int FlickWithHalleBerryID { get; set; }     

[ForeignKey("ComedyID")] public virtual Movie Comedy { get; set; }     
[ForeignKey("HorrorID")] public virtual Movie Horror { get; set; }     
[ForeignKey("DramaID")] public virtual Movie Drama { get; set; }     
[ForeignKey("SciFiID")] public virtual Movie SciFi { get; set; }     
[ForeignKey("FlickWithHalleBerryID")] public virtual Movie FlickWithHalleBerry { get; set; }
}

You’ll notice a little bit of funkiness going on there, but it’s really not that bad once you get your head around it. Let me explain what’s going on.

EF Code First and the MvcScaffolding bits are good and smart, but they still need to know stuff.  If we want our Views to light up correctly, MvcScaffolding needs to know how to render the model you’re trying to express.

You can boil the insanity down to a sort of key-pair model here. We need to store the id of the movie in the database but we also want to have the benefit of a rich model that knows about the movie entity being referenced.

Let’s look at just one key-pair sequence isolated from the rest:

public int ComedyID { get; set; }
[ForeignKey("ComedyID")] public virtual Movie Comedy { get; set; }

See, that’s not so bad, right!?

The ComedyID will be persisted to the database, while the Comedy movie object will not. We add the ForeignKey attribute for MvcScaffolding to clear up any confusing it might have mapping the object in its duties. Marking it virtual is a way of saying, “Hey, Mr. EF Code First groovy bits, please keep track of this object for me using the integer field I gave you, but when you load up my model, please include the full movie entity and not just a numerical field. K, thanks!”

Thanks, indeed, Mr. EF Code First groovy bits. Thanks, indeed.

Scaffold Intending to Fail

The only reason I want to fail here is to illustrate a current limitation of Code First. We can build up our project very quickly here, so make sure you have a good feel around the solution if you’re new to this so that you understand what’s going on.

Back in the Package Manager Console, type the following:

Scaffold Controller Movie -Repository

This little gem treats you to a coffee break while it creates your CRUD capable controller, your repository, the DB context object you want and fleshes out your views.  We’re going to do the same with FavoriteMovieProfile class now:

Scaffold Controller FavoriteMovieProfile -Repository

This does the same thing, but it respects that you already have a context in place and it just updates it as required.

Let’s run the project now and once it’s up, add a /Movies to your URL. The project will seem to run fine at first, but once you hit that movies view you should see this:

image

The database creation succeeded, but the creation of the database objects did not. See InnerException for details.

And when we check the inner exception for details…

Introducing FOREIGN KEY constraint ‘FavoriteMovieProfile_Drama’ on table ‘FavoriteMovieProfiles’ may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.

Ah, yes, that failure I was talking about.  So, here’s the deal. EF Code First doesn’t really have an elegant solution for several one-to-one mappings, or at least, not one that can be expressed with the fluent API or attributes alone. SQL Server will whine about trying to create the constraints, so we need to spoon feed it a bit.

I understand that spoon feeding in the future will be baked into EF Code First. Thankfully it’s not that big of a deal.

A Side-Step to Clean Up

Code First means that we get our data model for free, without having to create a database. The schema is implied through our object definitions, the attributes we provide, and any additional directions we throw at it through the fluent API.

For me, because I’m not using an SDF, the database was created (or at least, it was attempted to be created) in SQL Server Express, which I have running locally. We need to clean that up a bit.

While we’re about to employ a method that will clean up the database independently and automatically, we had a fail here and the metadata required to track changes was not correctly written to the database. You will need to manually delete the database at this time. If you’re looking, it’ll be named ProjectName.Models.DataContext (with appropriate nomenclature, mine was Movies.Web.Models.MoviesWebContext).

Go ahead. I’ll wait for you here to finish.

Extending our Movies Data Context

Once you remove the comments and add a little brevity to the model names, our MoviesWebContext class (found in the models folder) should look like this:

public class MoviesWebContext : DbContext
{     
public DbSet<Movie> Movies { get; set; }     
public DbSet<FavoriteMovieProfile> FavoriteMovieProfiles { get; set; }
}

We inherit from DbContext and define a couple of entity sets, each containing the models that we’ve scaffolded so far.  To this class, we’re going to override a method from our base class and put in a bit of our own helpers to get that database created more smoothly.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // …
}

In this method, we’ll add five lines like the following:

modelBuilder.Entity<FavoriteMovieProfile>()
   .HasRequired(m => m.Comedy)
   .WithMany()
   .HasForeignKey(m => m.ComedyID)
   .WillCascadeOnDelete(false);

You can see the mapping and likely get the idea. We mark the field as required and want to set up the foreign key, which requires the WithMany() call. This sets up a one-to-many relationship (which I mentioned above and will fix below) and also takes care of the cascade error with the false flag.  All five lines are as follows:

![image](http://oldblog.jameschambers.com/Media/Default/Windows-Live-Writer/MvcScaffolding-Joy-Ride-with-EF-Code-Fir_A43C/image_10.png "image")

Great, now that that’s out of the way, we have two small things to take care of: creating our own initializer and making sure it’s getting called at the appropriate time by our application.

Initializing the Database the Cool Way

Well, not so cool if you actually have real data in there, I suppose, but I digress.

What we’re going to do now is to add one more class to our application (you can just put it in the dbcontext file for now) that inherits from DropCreateDatabaseIfModelChanges. This is a class that can automatically detect changes to the schema. When it does, it proceeds to drop the DB and recreate it. In this class we override the Seed method and clean up our one-to-one mappings.

The entire class looks like this:

public class MoviesDbInitializer : DropCreateDatabaseIfModelChanges<MoviesWebContext>
{     
    protected override void Seed(MoviesWebContext context)     
    {         
    context.Database.ExecuteSqlCommand("ALTER TABLE FavoriteMovieProfiles ADD CONSTRAINT unique_Drama UNIQUE(DramaId)");
    context.Database.ExecuteSqlCommand("ALTER TABLE FavoriteMovieProfiles ADD CONSTRAINT unique_Comedy UNIQUE(ComedyId)");
    context.Database.ExecuteSqlCommand("ALTER TABLE FavoriteMovieProfiles ADD CONSTRAINT unique_HalleBerry UNIQUE(FlickWithHalleBerryId)");         
    context.Database.ExecuteSqlCommand("ALTER TABLE FavoriteMovieProfiles ADD CONSTRAINT unique_Horror UNIQUE(HorrorId)");         
    context.Database.ExecuteSqlCommand("ALTER TABLE FavoriteMovieProfiles ADD CONSTRAINT unique_SciFi UNIQUE(SciFiId)");     
    }
}

Basically, we’re just executing some SQL commands that take care of the part that EF can’t do on it’s own, creating our unique constraints.

Finally, drill into your Global.asax.ca file and add the following line of code in Application_Start():

Database.SetInitializer(new Movies.Web.Models.MoviesDbInitializer());

(You’ll also need to add System.Data.Entity to your using statements.)

Press F5 and add the /movies to your URL to play along.

image

Add a couple of movies, then switch up your url to /FavoriteMovieProfiles for kicks. When you create a new one it’ll look like this:

image

…and when you save it and return to the grid, it’ll look like this:

image

Very nice.  Only thing missing is “melo” in front of “Drama”.

Wrapping Up

This wasn’t hard at all, once we had the bits in place we needed.  We are talking about less than 30 lines of code here, and this isn’t the simplest of models. Powerful stuff.

The ASP.NET MVC Framework is getting better with each iteration as it continues to add functionality, convention and integration points with external libraries, even those from the open source community.

The addition of NuGet to our toolkit, while not yet perfect, is still a huge help and makes adding third-party resources a breeze.

The Swiss Army Knife of this trip is obviously the MvcScaffolding, which kicks out that boiler plate code that we’ve all come to be able to write in our sleep (but, obviously, it’s much more fun to have a tool do it).

And hey, I’m no tool.

To read more on this, visit:

These guys all have MVC coverage and infos on MvcScaffolding.

Cheers.

Moving Database Files in MS SQL Server

I was running into a disk space problem that was only revealed when I tried to restore a production database to the test environment that was several GBs bigger.

I updated the DB’s files to point to a new drive on the server, moved the files and restarted the service.  All good.

Then, as I attempted to restore the database, I kept getting files pace errors.

The problem? I had forgot to alter the restoration file location and SQL Management Studio was trying to use the original file path.

Here’s where you make the change:

image

When you go to Tasks –> Restore –> Database, select the Options page and change the target paths for your database files.

New Digs

I have been on the Blogger platform for years, but have decided to move over to Orchard so that I can further integrate code samples, pick and choose modules and widgets appropriate to my style and take advantage of (and hopefully contribute to) the already mature community around the Orchard engine.

I’m going to ride the default theme for a while as I get my bearings, and I don’t think I’m going to make much effort to port my old posts over to this site.

If you’re looking for the old Mister James site, you can find it at http://theycallmemrjames.blogspot.com.

Thanks for joining me!

MIX11: The Decompression Session

I am back from MIX11 in the sunny state of Nevada, an annual event hosted by Microsoft. This year’s conference was located at Mandalay Bay at the south end of the strip in Las Vegas.  MIX gave me a much needed energy refresh with some great speakers, some great content and wonderful conversation with folks in the industry.

As a result of the recharge I am moving my blog to this site and returning to working in and with the community to help other developers move their skillsets forward and get excited about what we’re able to do with the tools and resources available to us as software developers.

Want to know what it’s like to be at MIX?

Registration

This was actually one of my only complaints about the event.  I arrived in Las Vegas a day early and made my way to the registration area of the conference.  Security would have none of that (they were, in fact, quite rude and condescending) and told me to come back Monday at 9AM. 

Luckily I didn’t listen to them. Here’s what I saw when I arrived at 8AM.

image

And when I got through the line, a 40 minute adventure, the line extended out past the lounge areas, the “Commons”, around the corner and out to the escalators.  It was nuts. At the onset, it seemed as though there were only 4 lines moving, with over 35 people in each line and hundreds more moving in by the hour.

Registration staff were friendly and once they got their groove on, they seemed to chew through the line rather quickly.

Boot Camps

While there was added cost to the conference when attending the boot camps, I think that this was some of the most valuable learning at the show.  In particular, there were some great tandem presentations where you were able to gain some great insight into the workflow between designers and developers. This was especially handy for those of us who wear both roles.

Keynotes

On Tuesday and Wednesday the day began with a packed house event in the main ballroom at the conference center. Tuesday was the IE9 and HTML5 show, focusing on native-like applications on Windows and reinforcing the speed of IE9 versus the competition with some live demos.  While some of the content was impressive, the presenters were a little scattered and seemed to flip in and out of semi-random topics (for example, the Samsung laptop mention).

image

Wednesday’s keynote was nuts.  We saw IE9 running on Windows Phone 7 and it destroyed the iPhone 4.  I’m talking about hardware accelerated rendering support that took HTML5 samples and trounced Safari by a performance factor of 15 to 1. We got treated to a ton of information on the new APIs for WP7 and some interesting, exciting and at times hilarious demos of some of the tech available to us and coming in the near future. We should all have our hands on the new WP7 bits within weeks, as well as the SDK for the Kinect.

Which is why they gave every attendee a free Kinect.  Sweet!

Sessions

I was able to maximize my learning in the sessions, especially around web development tooling updates and the UX discussions. Some of the speakers are worth the price of admission for the entire event, and while I’ve seen some epic videos of these guys in the past, you really need to be there to see what happens before and after the taping!

The only thing I didn’t care for about the sessions was the organization, presentation and planning materials available to attendees.  There were no topical streams, and any particular room could vary greatly in topic from one time slot to the next. The map and session info (printed materials) were not well laid out and lots of folks were wondering trying to find the next session they wanted to attend.

Extra Perks

I was pleased to be invited by Microsoft Canada to the Tao VIP room at the Venetian hotel. Wowsers. Free-flowing bar, very classy appetizers and samples all night, hands-on tech demos, great conversation and face-to-face time with other Canadian developers and Microsoft folks. This was probably the most energizing event for me because of some of the connections I was able to make and the chance to catch up with some folks I hadn’t seen in a while.

The Grub

I have never eaten at any conference or training event like I did at MIX11. The food was incredible. It was professional prepared, presented and served.  Though it was buffet style self-service, the staff ushered attendees through the line and you got to the food quickly while temperature was still excellent. There was fish, chicken, beef and vegetarian options (as well as some other specialized menus) and all kinds of fresh fruit, salad, dressings, fixings, sides and the like.  I cannot stress enough that most of the food had no business being on a buffet line!

The Haul

Conferences aren’t just about the learning. At MIX this year I learned just how much we geeks love us some free shirts. I literally saw grown men standing on chairs shouting “Me! Me!”.  So, yes, of course there was loot! You could get lanyards, t-shirts, hoodies, photo-booth photos, goofy Windows Phone 7 desktop mascots, pens, mouse pads and more. But the real thrill was getting a free Kinect after the keynote on Wednesday.

And, Yes, The Strip

What would a trip to Las Vegas be without a trip down the strip? Here are some of the sights we were able to take in.

image  image  image image

New York, New York, Excalibur, and a couple shots of the Bellagio.

Final Thoughts

I was so fortunate that my wife was able to join me for this event. We’ve been together for over 15 years, but she’s still such a great sport when, environmentally, I have no choice but to geek out. She was able to enjoy herself through the shops and hotels along the strip while I was in conference, but we also got some great nights in together and took advantage of our first trip away from kids since we were married over a decade ago (at least, without the kids!).

While this post tried to get you into what MIX was like to attend I haven’t really covered the tech side of what I took in. I am looking forward to development in the weeks ahead and will be writing about some of the great resources that have advanced, been released or will be soon.

This conference had a wide enough spectrum to bring in a great cross section of the development community as well as some great minds in design.  If you are involved in the UI, UX or supporting backend bits this is a great chance to catch up on the new tech, take a deep dive into the existing tools, see a little more clearly the road ahead and to interact with a great community.

Hope to see you there next year!