.NET 4 ships with a muchimproved version of Entity Framework (EF) – a data access library thatlives in the System.Data.Entity namespace.
When EntityFramework was first introduced with .NET 3.5 SP1, developers provided alot of feedback on things they thought were incomplete with that firstrelease. The SQL team did a good job of listening to this feedback, andreally focused the EF that ships with .NET 4 on addressing it.
Some of the big improvements in EF4 include:
- POCO Support: You can now define entities without requiring base classes or data persistence attributes.
- Lazy Loading Support: You can now load sub-objects of a model on demand instead of loading them up front.
- N-Tier Support and Self-Tracking Entities: Handle scenarios where entities flow across tiers or stateless web calls.
- Better SQL Generation and SPROC support : EF4 executes better SQL, and includes better integration with SPROCs
- Automatic Pluralization Support : EF4 includes automatic pluralization support of tables (e.g. Categories->Category).
- Improved Testability : EF4’s object context can now be more easily faked using interfaces.
- Improved LINQ Operator Support : EF4 now offers full support for LINQ operators.
VisualStudio 2010 also includes much richer EF designer and tooling support.The EF designer in VS 2010 supports both a “database first” developmentstyle – where you construct your model layer on a design surface from anexisting database. It also supports a “model first” development style –where you first define your model layer using the design surface, andcan then use it to generate database schema from it.
Code-First Development with EF
In addition to supporting a designer-based development workflow, EF4 also enables a more code-centricoption which we call “code first development”. Code-First Developmentenables a pretty sweet development workflow. It enables you to:
- Develop without ever having to open a designer or define an XML mapping file
- Define your model objects by simply writing “plain old classes” with no base classes required
- Use a “convention over configuration” approach that enables database persistence without explicitly configuring anything
- Optionally override the convention-based persistence and use a fluent code API to fully customize the persistence mapping
EF’s“code first development” support is currently enabled with a separatedownload that runs on top of the core EF built-into .NET 4. CTP4 ofthis “code-first” library shipped this week and can be downloaded here.
It works with VS 2010, and you can use it with any .NET 4 project (including both ASP.NET Web Forms and ASP.NET MVC).
Step by Step Tutorial: Building NerdDinner using a Code-First Approach
Last year I wrote an ASP.NET MVC 1.0 tutorial that was published both onlineand in a book. The tutorial walked through creating a simpleapplication, called “NerdDinner”, which provides an easy way for peopleto organize, host and RSVP for dinners online. You can read my originalASP.NET V1 NerdDinner tutorial here. An updated version of the tutorial is also included in the new Professional ASP.NET MVC 2 book.
TheNerdDinner tutorial used a “database first approach” where the databaseschema was defined first, and then we used a Visual Studio designer tocreate our LINQ to SQL / LINQ to Entities model objects that mapped toit.
Below I’m going to demonstrate how we could instead usea “code first approach” using EF4 to build the NerdDinner model layerand database schema, and construct a CRUD application using ASP.NET MVC.
Wewill walkthrough building this application step-by-step. A downloadlink to a completed version of the sample is available at the end ofthis blog post.
Step 1: Create a New Empty ASP.NET MVC 2 Application
We’llstart by creating a new ASP.NET MVC 2 Project within Visual Studio2010. Choose File->New Project and use the “ASP.NET MVC 2 Empty WebApplication” project template to do this.
This will create an empty ASP.NET MVC 2 project that does not have any controllers, models or views within it:
We’llnext work to define our NerdDinner “model” – which refers to theobjects that represent the data of our application, as well as thecorresponding domain logic that integrates validation and business ruleswith it. The model is the "heart" of an MVC-based application, andfundamentally drives the behavior of it. We’ll create this model layerusing the new EF4 “Code First” capabilities.
Step 2: Create our Model
Let’sassume we do not already have a database defined, and that we arebuilding our new NerdDinner application completely from scratch.
We do not need to start with a database
When using a code-first development workflow, we do notneed to begin our application by creating a database or specifyingschema. Instead we can begin by writing standard .NET classes thatdefine the domain model objects that are most appropriate for ourapplication – without having to worry about intermixing data persistencelogic within them.
Creating Model Classes
NerdDinneris a small application, and our data storage needs with it are prettysimple. We want to be able to define and store “Dinners” that refer tospecific events that people can attend. We also want to be able todefine and store “RSVP” acceptances, which are used to track a person’sinterest in attending a particular Dinner.
Let’s create twoclasses (Dinner and RSVP) to represent these concepts. We’ll do this byadding two new classes to our ASP.NET MVC project - “Dinner” and“RSVP”:
The above “Dinner” and “RSVP” model classes are “plain old CLR objects” (aka POCO). They do notneed to derive from any base classes or implement any interfaces, andthe properties they expose are standard .NET data-types. No datapersistence attributes or data code has been added to them.
Theability to define model classes without having to tie them to aparticular database, database API, or database schema implementation isreally powerful – and provides us with much more data accessflexibility. It allows us to focus on our application/business needswithout having to worry about persistence implementation. It also givesus the flexibility to change our database schema or storageimplementation in the future – without having to re-write our modelobjects, or the code that interacts with them.
Creating a Context Class to Handle Database Persistence
Nowthat we’ve defined our two POCO model classes, let’s create a classthat we can use to handle the retrieval/persistence of Dinner and RSVPinstances from a database.
We’ll name this class“NerdDinners”. It derives from the DbContext base class, and publishestwo public properties – one that exposes our Dinner objects, and onethat exposes our RSVP objects:
TheDbContext and DbSet classes used above are provided as part of the EF4Code-First library. You’ll need to add a reference to theSystem.Data.Entity.CTP assembly that is installed into the \Program Files\Microsoft ADO.NET Entity Framework Feature CTP4\Binariesdirectory to reference these classes. You’ll also want to add a “usingSystem.Data.Entity” namespace statement at the top of your“NerdDinners” class file.
That is all the code we need to write
The above three classes contain all of the code necessary to implement a basic model and data persistence layer for our NerdDinner application. We do notneed to configure any additional database schema mapping information,nor run any tools, nor edit any XML files, nor use any designers inorder to start using our classes to retrieve, update, and save data intoa database.
Convention Based Persistence Mapping
Wedo not need to write any additional code, nor create any XML files, noruse any tools in order to map our model classes to and from adatabase. How, you might ask, is that possible?
By default,EF code-first supports a “convention over configuration” approach thatenables you to rely on common mapping conventions instead of having toexplicitly configure things. You can override theseconventions if you want to provide custom database mapping rules. Butif you instead just use the default conventions you’ll find that theamount of code you have to write is really small, and the common 90% ofscenarios “just work” the way you’d expect them to without any extracode or configuration.
In our example above, our NerdDinnerscontext class will by default map its “Dinners” and “RSVPs” propertiesto “Dinners” and “RSVPs” tables within a database. Each row within theDinners table will map to an instance of our “Dinner” class. Likewise,each row within the RSVPs table will map to an instance of our “RSVP”class. Properties within the “Dinner” and “RSVP” classes in turn map tocolumns within the respective “Dinners” and “RSVPs” database tables.
Otherdefault conventions supported by EF include the ability toautomatically identify primary-key and foreign keys based on commonnaming patterns (for example: an ID or DinnerID property on the Dinnerclass will be inferred as the primary key). EF also includes smartconventions for wiring-up association relationships between models. TheEF team has a blog post that talks more about how the default set ofconventions work here.
Code Examples of How to Use Our Model
The three classes we created earlier contain all of the codenecessary to implement our model and data persistence for NerdDinner. Let’s now look at a few code examples of how we can use these classes toperform common data scenarios:
Query Using LINQ Expressions
Wecan write LINQ query expressions to retrieve data from a database usingthe following code. Below we are using a LINQ expression to retrieveall dinners that occur in the future:
Wecan also take advantage of relationships between Dinners and RSVPs whenwriting our LINQ expressions. Notice below how our “where” statementfilters by dinners whose RSVP count is greater than 0:
Notethat the “where” filter in the above query (where we are retrievingonly those Dinners who have at least one RSVP) executes in the databaseserver – making the query and the amount of data we retrieve veryefficient.
Retrieving a Single Instance
We can use LINQ’s Single() method with a lambda query to retrieve a single instance of a Dinner using code like below:
Alternatively,we can also take advantage of a Find() method that EF “code-first”exposes that allows you to easily retrieve an instance based on its ID:
Adding a new Dinner
Thecode below demonstrates how to create and add a new Dinner to thedatabase. All we need to do is to “new” a Dinner object, set propertieson it, and then add it to the Dinners property of our NerdDinnerscontext object. The NerdDinner context class supports a “unit of work”pattern that enables you to add multiple models to the context, and thencall “SaveChanges()” on it to persist all of the changes to a databaseas a single atomic transaction.
Updating a Dinner
Thecode below demonstrates how to retrieve a Dinner, update one of itsproperties, and then save the changes back to the database:
Step 3: Create a ASP.NET MVC Controller that uses our Model
Let’snow look at a more complete scenario involving our model, where we use acontroller class to implement the functionality necessary to publish alist of upcoming dinners, and enable users to add new ones:
We’llimplement this functionality by right-clicking on the “Controllers”folder and choose the “Add->Controller” menu command. We’ll name ournew controller “HomeController”.
We’ll then add three “action methods” within it that work with the NerdDinners model we created earlier using EF “Code-First”:
The “Index” action method above retrieves and renders a list of upcoming dinners.
The“Create” action methods allow users to add new dinners. The first“Create” method above handles the “HTTP GET” scenario when a user visitsthe /Home/Create URL, and send back a “New Dinner” form to fill out. The second “Create” method handles the “HTTP POST” scenario associatedwith the form – and handles saving the dinner in the database. If thereare any validation issues it redisplays the form back to the user withappropriate error messages.
Adding Views for our Controllers
Our next step will be to add two “View templates” to our project – one for “Index” and one for “Create”.
We’lladd the “Index” view to our project by moving our cursor within theIndex action method of our controller, and then right-click and choosethe “Add View” menu command. This will bring up the “Add View” dialog. We’ll specify that we want to create a strongly-typed view, and that weare passing in a IEnumerable list of “Dinner” model objects to it:
When we click “Add”, Visual Studio will create a / Views/Home/Index.aspxfile. Let’s then add the following code to it – which generates a
list of Dinners, and renders a hyperlink that links to ourcreate action:
We’llthen add the “Create” view to our project by moving our cursor withinthe Create action method of our controller, and then right-click andchoose the “Add View” menu command. Within the “Add View” dialog we’llspecify that we want to create a strongly-typed view, and that we arepassing it a Dinner object. We’ll also indicate that we want to“scaffold” using a “Create” template:
When we click “Add”, Visual Studio will create a /Views/Home/Create.aspxfile with some scaffold-generated content within it that outputs anHTML