Note that this works just as well with MVC4 as it does MVC3.
So, when is Code First not Code First?
It is possible, even recommended, to use ‘code first’ techniques even when you are not generating the database from the code. This is hinted at in the Creating an Entity Framework Data Model for an ASP.NET MVC Application article on Microsoft’s asp.net web site (http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application). The code first technique will mean that you are using POCO classes for the models which are persistence ignorant.
An example to show you how this is achieved…
The first step is to create a SQL database called Bank. I used SQL Express for my test. Then within the database create a table called Customer, you can use the following SQL statement to do this:
CREATE TABLE Customers( CustomerID int IDENTITY(1,1) NOT NULL, FirstName nvarchar(50) NOT NULL, LastName nvarchar(50) NOT NULL, Title nvarchar(10) NOT NULL, HomePhone nvarchar(20) NULL, CONSTRAINT PK_PrivateCustomer PRIMARY KEY CLUSTERED (CustomerID ASC))
Insert a couple of dummy records so we will be able to test we are correctly connected:
INSERT Customers (FirstName, LastName, Title, HomePhone) VALUES ('John', 'Jones', 'Mr', NULL) INSERT Customers (FirstName, LastName, Title, HomePhone) VALUES ('Steve', 'Smith', 'Mr', '01023123123')
Now create yourself an MVC3 project called Bank in Visual Studio.
Create yourself a BankContext.cs class, I put this in a folder called DAL but you can leave it in the Models folder if you desire. This class should have the following contents:
using System.Data.Entity; namespace Bank.Models { public class BankContext : DbContext { public DbSet Customers { get; set; } } }
You then need to setup a connection to your database in your web.config, by using convention and calling it BankContext there will be no other code to add, for example:
<add name="BankContext" connectionString="Data Source=.\SQLExpress;Initial Catalog=Bank;Integrated Security=True" providerName="System.Data.SqlClient" />
Create a class in the Model folder called Customer.cs and change it’s contents to the following:
namespace Bank.Models { public class Customer { public int CustomerID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Title { get; set; } public string HomePhone { get; set; } } }
Build the project.
To see the results we need to create a controller and views. Right-click on the Controllers folder and choose to add a new controller. Call the controller ‘CustomerController’, make it use the template ‘Controller with read/write actions and views, using Entity Framework’, set the model class to ‘Customer (Bank.Models)’, and set the data context class to ‘BankContext (Bank.Models)’.
Now run the application and once it has started add “/customer” to the end of the url (e.g. http://localhost:21032/customer). You should see the customer index page listing the customers you created earlier in the database.
That is all there is to the basics of using code first techniques with an existing database.
Mapping
The above simple example works flawlessly because we are in full control of the names of the tables, columns, classes and properties, however, in the real world we are likely to have table or column names that do not map nicely to names we want for our classes and properties, and in this case we need to map one to the other.
Microsoft provides two ways of dealing with the problem of having table names different to our class names (column names are also treated in a similar way). We can use Data Annotations where we put attributes in the class and reference System.ComponentModel.DataAnnotations, or we can use the Fluent API.
The use of Data Annotations has the advantage of keeping everything together and is in some ways easier to understand and maintain, but it has the disadvantage of introducing a dependency that means we no longer are using true POCOs.
This is what our class might look like if we were to use Data Annotations to specify the table name to use:
using System.ComponentModel.DataAnnotations; namespace Bank.Models { [Table("Customers")] public class Customer { public int CustomerID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Title { get; set; } public string HomePhone { get; set; } } }
We can achieve the same results using the Fluent API, it takes more code but it means we maintain our POCOs in a pure state. The first step is to create a mapping class for each model to map between the model and the database, in this case we will create a CustomerMap class that looks like this:
using System.Data.Entity.ModelConfiguration; public class CustomerMap : EntityTypeConfiguration { public CustomerMap() { ToTable("Customers"); } }
We also need to make a change to the DbContext class so that OnModelCreating will load our mapping.
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new CustomerMap()); }
The Fluent API is very flexible and allows you to achieve much more than simply defining the mapping between table/column names and class/property names.
Validation
Model validation such as defining the maximum length for string properties can also be achieved using Data Annotations or the Fluent API. Use of Data Annotations for validation properties doesn’t break the POCOs in the same way as it does for database mappings but gives you an enriched model that is understood by the views when validating user input. You may of course prefer to use view models to add a further layer of separation and keep your POCOs clean.
Further Information
Jon Galloway in one of his blogs (Generating EF Code First model classes from an existing database – <a href=”http://weblogs.asp.net/jgalloway/archive/2011/02 premarin medication.aspx”>http://weblogs.asp.net/jgalloway/archive/2011/02.aspx) suggests an easy way of generating the POCOs using a Microsoft tool, the EF 4.x DbContext Generator. I have tried this ‘Microsoft way’ and it works pretty well.
A tool called ST4bby has been recommended to me that does the same thing, I have not used this myself.
Adam Nelson suggested that by using the “Entity Framework Power Tools” you get the attributes for free. This is a great tool that builds the Fluent API mappings for you by referencing an existing database. It does not yet allow you to only generate part of a database or use Data Annotations rather than the Fluent API.