Monday, May 10, 2010

Entity Framework 4.0 Walk-through

This example is a walk-through the basic characteristics of Entity Framework 4.0.  In this example we'll see how to perform the following:
  • Create an Entity Framework 4.0 based application with Visual Studio 2010.
  • Model First Development by creating your Entity Model first and then generate DDL to create the database with maching tables and relations.
  • Create relations (associations) between entities.
  • Create a Mount database batch file that will run our script to create our database and its objects.
  • Execute CRUD operations (Create, Read, Update, Delete) over our database.
Let's start by creating a new Class Library project and add an ADO.NET Entity Data Model.

When the Entity Data Model Wizard dialog appears, choose an Empty Model content.

Add the two Entities (Role and User) that will represent our database tables for this example.  If the database had already existed, we can choose Update Model from Database and select the objects from our database such as tables, stores procedures and functions.

Add the Properties needed to define each Entity. In the properties window we can define type, size and nullability for each property.
Create Association between the entities Role and User.  Right click on the Entity Role and select Add -> Association.
After the Association is added, it can be configured in the properties window or open the Referential Constraint window by double clicking on it.
To view the definition of the table that will be created in the database, we can select the Entity, right click on it and select Table Mapping.
The create database DDL can be generated from the Model by right clicking on it and selecting Generate Database from Model.  If the database existed just click on Update Model from Database and select database objects.
When Generate Database Wizard dialog appears, specify a name for the new ConnectionString that will be added to a configuration file in the application.
After clicking the Next button in the Generate Database Wizard it will generate the SQL script to create database objects from the Model.
Create a batch file and added as an external tool in the Visual Studio.  It will run the Create Database script (manually added) and the one generated by Entity Framework.  This can be easily run each time the Model or Database is modified.
After building the application and clicking the button to show all files, there are three files generated.  The Conceptual schema definition language (CSDL), store schema definition language (SSDL), and mapping specification language (MSL) which are XML-based languages that respectively describe the conceptual model, storage model, and the mapping between these models. These files are generated at build time and the EF needs them at run time.
The EF4DomainModel.Designer.cs was created with the EDMX file.  This file contains the Context, Entities and Types generated by the code generator defined by default in the Custom Tool property of the EDMX file.
Now let’s write some code to test the application with CRUD operations.
  • Add a Console Application to the solution.
  • Copy the App.config and pasted to the Console Application.
  • Create a folder name Temp and Add a TestCrudeOperations.cs class.

In the class TestCrudeOperations.cs add the code bellow. This is what we're doing:
  • Insert all the Roles and Users to the database.
  • Update User information.
  • Read and List the three inserted Users.
  • Read a property a Million times to measure performance in milliseconds.
  • Delete all the Roles and Users from the database.
We have to call the method SaveChanges() from our context to commit our changes to our database.
using System;
using System.Linq;
namespace EF4Application.Temp
{
    public class TestCrudeOperations
    {
        public void RuntTest()
        {
            using (var context = new EF4DomainModelContainer())
            {
                Console.WriteLine("INSERTING ROLES TO DATABASE");
                context.AddToRoles(new Role { RoleName = "Role 1" });
                context.AddToRoles(new Role { RoleName = "Role 2" });
                context.AddToRoles(new Role { RoleName = "Role 3" });
                context.SaveChanges();

                Console.WriteLine("INSERTING USERS TO DATABASE");
                var firstRole = context.Roles.Where(t =>t.RoleName=="Role 1").FirstOrDefault();
                context.AddToUsers(
                    new User
                    {
                        UserName = "user1",
                        FirstName = "FirstName1",
                        LastName = "LastName1",
                        DateOfBirth = new DateTime(1980, 12, 10),
                        Role = firstRole
                    });
                var secondRole = context.Roles.Where(t =>t.RoleName=="Role 2").FirstOrDefault();
                context.AddToUsers(
                    new User
                        {
                            UserName = "user2", 
                            FirstName = "FirstName2", 
                            LastName = "LastName2", 
                            DateOfBirth = new DateTime(1980, 12, 11), 
                            Role = secondRole
                        });
                var thridRole = context.Roles.Where(t =>t.RoleName=="Role 3").FirstOrDefault();
                context.AddToUsers(
                    new User
                        {
                            UserName = "user3", 
                            FirstName = "FirstName3", 
                            LastName = "LastName3", 
                            DateOfBirth = null, 
                            Role = thridRole
                        });
                context.SaveChanges();

                Console.WriteLine("UPDATING USER INFORMATION");
                var user1 = context.Users.Where(t => t.UserName == "user1").FirstOrDefault();
                user1.FirstName = "Alexandro";
                user1.LastName = "Velarde";
                context.SaveChanges();

                Console.WriteLine("VIEW INSERTED USERS");
                var users = context.Users;
                foreach (var u in users)
                {
                    Console.WriteLine(string.Format(
                        "UserName = {0}, FirstName = {1}, LastName = {2}, DateOfBirth = {3}",
                        u.UserName, u.FirstName, u.LastName, 
                        u.DateOfBirth.HasValue ? u.DateOfBirth.Value.ToString("MM/dd/yyyy") 
                        : string.Empty));
                }

                Console.WriteLine("PERFORMANCE TEST STARTED...");
                var user = users.FirstOrDefault();
                string readValueOneMillionTimes = null;
                var timeWhenTestStarted = DateTime.Now;
                for (int i = 0; i < 1000000; i++)
                {
                    readValueOneMillionTimes = user.Role.RoleName;
                }
                var duration = DateTime.Now.Subtract(timeWhenTestStarted);
                Console.WriteLine("VALUE READ: " + readValueOneMillionTimes + 
                                  " DURATION: " + duration.TotalMilliseconds + " MILLISECONDS");
                Console.WriteLine("PERFORMANCE TEST END");

                Console.WriteLine("DELETE USERS FROM DATABASE");
                foreach (var userToDelete in context.Users)
                    context.DeleteObject(userToDelete);

                foreach (var role in context.Roles)
                    context.DeleteObject(role);
                context.SaveChanges();
                Console.ReadKey();
            }
        }
    }
}
In the Console Application, let’s write the following code in the Main method.
This are the test results in the Console Application.
From the SQL Management Studio, if we do a select to both tables Roles and Users, we’ll see the following results.

Conclusion
With this post we were able to execute and persist data in our database.  The performance test is intented to be compared after, when we see POCO classes.

What's next?
As always, I'm opened to suggestions...for now, this is what I have in mind for next posts: POCO classes and templates for code generation, Change Tracking with POCO (Snapshot and Notification based), Implementing Repository and Unit of Work pattern with Entity Framework 4.0., etc..


7 comments:

  1. 4 secs for 1 Million iterations is BAD!
    I am expecting the POCO approach to be a lost faster!

    ReplyDelete
  2. Thanks Alexandro. Very well done. Took less than 10 minutes though.

    ReplyDelete
  3. Thank you Riad, soon I will post an example on POCO classes with the same performance test to see the big difference

    ReplyDelete
  4. Hi Behnam, thank you for the comment on my 10 minutes theory :-). Follow up, you'll have some good examples on POCO classes soon...

    ReplyDelete
  5. It's a good introduction will there be more advance case for future blog?

    ReplyDelete
  6. Hi Martin, thank you for your comment.
    There will be more advance cases as mentioned at the end of my post. I'll do my best to post one every week.
    Thanks..

    ReplyDelete