Archive

Posts Tagged ‘MVC’

MVC 3 and Entity Framework Code First

12 October 2011 Leave a comment

In this post I will cover the basics of getting started with Entity Framework using code first.  I will assume familiarity with Visual Studio and MVC projects.

To get started I:

  1. created a new MVC 3 application in Visual Studio
  2. chose internet application – either will do
  3. selected the Razor View Engine
  4. selected Html 5 markup

So now we have the bog standard default MVC website.  Since Entity Framework now comes standard with MVC there is no need to install any additional packages and we can start playing straight away.

Just to do something a bit different I will create an application that allows you to add/edit/delete/list solar systems which can contain planets.  For the sake of simplicity I will not create interfaces.

Now, let the coding being…

Add two new areas called SolarSystem and Planet.  In SolarSystem’s Model folder we add a class called SolarSystem and in Planet’s Model folder we add one called Planet.  The model called the same as the containing namespace is a dumb idea, I know, but for this post I will just keep it that way.  Below is the code for the models.  You can see in the planet model we have SolarSystem as well as SelectedSolarSystemId.  This will be more obvious later on but it is used for the UI to automagically create a list of solar systems for selection when creating or updating a planet.

public class Planet
{
    [Key]
    public int Id { get; set; }

    [Required]
    [StringLength(150)]
    public string Name { get; set; }

    [Required]
    public int SolarSystemId { get; set; }

    public SolarSystem.Models.SolarSystem SolarSystem { get; set; }
}

public class SolarSystem
{
    [Key]
    public int Id { get; set; }

    [Required]
    [StringLength(150)]
    public string Name { get; set; }
}

For Entity Framework to pick up the new models we have to rebuild the application first.

Now the magic begins.  Right-click on the Controllers folder for the Planet area and select the option to add a new controller.  In the popup (below) form enter the name as PlanetController then in the scaffolding options select the template “Controller with read/write actions and views, using Entity Framework”.  Also select our model, Planet in this case, and select “<New data context…>” from the Data context class option and enter a name, DataContext in my case.  Double check that you entered a controller name and then click add.  Forgetting the controller name is a very easy mistake to make.
If you get an error that the metadata could not be read then you most probably do not have accessible properties or you have selected a class from another namespace.  Then, once you select the model it will create a whole lot of good stuff…just about enough to replace developers…but this will now contain errors mixing up the namespace and the model so you will have to manually qualify your models in the controller actions to contain the namespace (or just name them right from the start).
Now do the same for SolarSystem but select the existing DataContext class that was created instead of a new one…and remember to double check that a controller name was entered. 

New controller popup

We will add buttons to the default layout to access the areas easily.  Do this by adding the following code to the _layout.cshtml in the shared views folder in the main application (myapp\Views\Shared\) just after the existing default buttons.

<li>@Html.ActionLink("Planets", "Index", "Planet", new { area = "Planet" }, null)</li>
<li>@Html.ActionLink("Solar Systems", "Index", "SolarSystem", new { area = "SolarSystem" }, null)</li>

If you run the application now you will be able to navigate to the areas and create new planets and solar systems.  In a few minutes we have created a fully fletched, albeit ugly, CRUD website.  A few tweaks and the UI can look fairly decent.

Note that if you are running into problems with database connection then make sure you have SQL Server Express running, it uses that by default.  Or sort out a connection string that works.  I ran into this and it took me a while to figure out what the problem actually was.

One thing I do not like, at all, is the ViewBag that is used in the planet controller.  This should be done using an editor template with a viewmodel instead…but that would take significantly longer to accomplish.

So, now we have an application running, what’s next I hear you say?  Data…default test data populated each time the database is recreated.  And a custom database name!  Also, once the database has been created it will not by default recreate the database when a model is changed which will cause the application to crash.  This is also covered below.

We will start by adding a default constructor to the DataContext class that pass a string containing the database name of your choice to it’s base class (DbContext).

public DataContext()
: base("SomeCustomDatabaseName")
{}

In order to create some test data each time the database is created we will override the OnModelCreating method in the DataContext class.  We will then have the following:

public class DataContext : DbContext
{
    public DataContext()
        : base("SomeCustomDatabaseName")
    {}

    public DbSet<Planet> Planets { get; set; }
    public DbSet<SolarSystem> SolarSystems { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer(new CustomDataContextInitializer());
        base.OnModelCreating(modelBuilder);
    }
}

CustomDataContextInitializer needs to be created and needs to inherit from different classes depending on whether you want to drop and recreate the database each time you run the app or only when a model changes.  In this example I will just let it recreate it every time the application is run and thus inherit from DropCreateDatabaseAlways<DataContext> instead of DropCreateDatabaseIfModelChanges<DataContext>.  Then for inserting data into the database we need to override the Seed method as follows.

internal class CustomDataContextInitializer : DropCreateDatabaseAlways<DataContext>
{
    protected override void Seed(DataContext dbContext)
    {
        base.Seed(dbContext);

#region Add Solar System
        SolarSystem solarSystem = new SolarSystem
        {
            Id = 0,
            Name = "The Sol System"
        };

        dbContext.SolarSystems.Add(solarSystem);
#endregion

#region Add Planets
        IList<Planet> planets = new List<Planet>
        {
            new Planet
            {
                Id = 0,
                Name = "Earth",
                SolarSystem = solarSystem
            },
            new Planet
            {
                Id = 1,
                Name = "Mars",
                SolarSystem = solarSystem
            },
            new Planet
            {
                Id = 2,
                Name = "Saturn",
                SolarSystem = solarSystem
            }
        };

        planets.ToList<Planet>().ForEach(planet => dbContext.Planets.Add(planet));
#endregion
        // The important bit
        dbContext.SaveChanges();
    }
}

Now when you run your application it will populate the database with your test data which you can go mad on…and it will all be reset when you restart your application.  Amazing stuff!

Now all you need to do is decorate your models with the badly needed data annotations and some CSS.

MVC Buddy Class

26 January 2010 5 comments

My latest “toy” is the new .NET 4.0 and MVC framework which has a few really nice additions.  In this post I will briefly cover one of them, Buddy Classes.  Although there are disagreements as to whether or not this is a good or bad thing, I like the fact that it makes life a bit simpler on smaller projects.

First off I created a VERY simple database with one table.

CREATE TABLE [dbo].[Friend](
	[UserId] [int] IDENTITY(1,1) NOT NULL,
	[FirstName] [nvarchar](100) NOT NULL,
	[LastName] [nvarchar](100) NOT NULL,
	[BirthDate] [date] NOT NULL,
 CONSTRAINT [PK_Friend] PRIMARY KEY CLUSTERED 
(
	[UserId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

This table will just hold a list of people.  The BrithDate column is not really for this post but for a later one where I will demonstrate how to use user controls for editing specific data types.

Then I added my ADO.NET Entity Data Set, in my Model folder, which created an object for this table.  As we all know, if I change this class the changes will be replace every time it is re-generated.  This is a problem when you want to add some attributes to the class.  What the guys at Microsoft has done is given us a way (hacky some say) to get passed this problem.   With this new feature we can simply create a Buddy Class (normal class in the Model folder) and decorate it to look like this:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;

namespace MVCBuddyClass.Models
{
    [MetadataType(typeof(FriendMeta))]
    public partial class Friend
    {
    }

    public class FriendMeta
    {
        [DisplayName("First Name")]
        public string FirstName { get; set; }
        [DisplayName("Last Name")]
        public string LastName { get; set; }
        [DisplayName("Date of Birth")]
        public DateTime BrithDate { get; set; }
    }
}

In this code you will notice the public partial class Friend, which has the same name as the partial class generated by the Entity Framework.  My own Friend class in this case gets the attribute [MetadataType(typeof(FriendMeta))] which you need using System.ComponentModel.DataAnnotations; for.  This hooks it up to my “buddy” class, FriendMeta.
FriendMeta contains all the properties with their attributes that we want to set, like DisplayName("First Name")] in this case.  There are many other attributes that you can set which more of will be covered in later posts, this one was simply to display the basic idea of a buddy class.

This should only be used for classes that get auto-generated to keep DRY.