1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
More than one way to skin a cat Introduction It has been almost 2 years since I wrote the Entity Framework crib sheet article for Simple-Talk. At that time, ADO.NET Entity Framework was an object-relational mapping technology (ORM) that supported the most basic database-interactions. In the upcoming Visual Studio.NET 2010, the ADO.NET Entity Framework 4 (actually version 2) has grown to support many new features, and to accommodate different development approaches. This article describes some of the different ways in which you can develop the data access layer for your application using Entity Framework, and some of the decisions that you would need to make. This article is based on the Visual Studio.NET 2010 Release Candidate (RC) version and ADO.NET Entity Framework CTP 3 available for download at the following URL Microsoft ADO.NET Entity Framework Feature Community Technology Preview 3. The 'Code First' section described in this article uses the ADO.NET Entity Framework CTP 3, since it is not shipped along with Visual Studio.NET 2010 RC ADO.NET Entity Framework - RecapLet us just do a quick introduction to the version of ADO.NET Entity Framework that we will be using throughout this article. ADO.NET Entity Framework requires a model. A model is a combination of 3 files: the conceptual schema, the storage schema and the mapping schema. The conceptual schema describes your business entities and the storage schema describes your database schema. The mapping schema is the glue that binds the conceptual schema to the storage schema by describing how the business entities translate to the database schema and vice versa. The other important artifacts in an ADO.NET Entity Framework data access layer are your code for the entities, and your database itself. For the purpose of this article we'll be working on a simple domain model. Let's assume that we are developing a simple task management application for the projects we do. In this application, a project can have many tasks, and a task can be a simple task or a critical task. A critical task has a due date. Which came first? The Model or the DatabaseThe choice of approach that you take in developing your data access layer will be different, depending on whether you are developing your data access layer for an existing database. If you already have a database to which you want to create your data access layer for, then you can create the model from the database: otherwise you can create the model independently from the database and then either generate the database from the model or map the model to the database. Model FirstWhen you add an ADO.NET Entity Data Model to your project you will get the following dialog box: When you choose an empty model, you will be presented with an empty surface where you can create the entities and the relationships between them. After creating your entities you can right click the design surface and you will get an option to generate the database from the model. This will add a SQL script to your project that has the necessary SQL statements to generate the database. The script also includes the following statements to create the tables for the above entities: -- Creating table 'Projects'CREATE TABLE [dbo].[Projects] ( [Id] int IDENTITY(1,1) NOT NULL, [Name] nvarchar(max) NOT NULL);GO -- Creating table 'Tasks'CREATE TABLE [dbo].[Tasks] ( [Id] int IDENTITY(1,1) NOT NULL, [Description] nvarchar(max) NOT NULL, [Project_Id] int NOT NULL);GO -- Creating table 'Tasks_CriticalTask'CREATE TABLE [dbo].[Tasks_CriticalTask] ( [DueBy] datetime NOT NULL, [Id] int NOT NULL);GO Database First The second option is to generate the model from the database. This is useful when you have already created a database with the necessary tables and you want to start off with a model based on the existing database schema. In this instance, when you add an ADO.NET Entity Data Model to your project you will select the option to generate model from database and point to an existing database. This will create the entities and the model, based on the database schema. There will be a problem with this approach: Your entities will not be rich in terms of your object model and will have a lot of direct one-to-one mapping with your tables. This could result in you having to use the tools provided with Visual Studio.NET to tweak your entities a lot, so as to change the mappings. Generated code or Handcrafted codeAnother decision that you will take when developing your data access layer is whether to go for Handcrafted code or to use code generation instead. ADO.NET Entity Framework makes use of a code generation technology called T4. T4 stands for Text Template Transformation Toolkit and is used in most of the places where designers are used to generate code within in Visual Studio.NET such as in LINQ to SQL. Generated codeWhen you add an ADO.NET Entity Framework Model to your project and begin to create entities, the T4 template will start generating code for the entities and the context. One of the biggest advantages in ADO.NET Entity Framework 4 is that the template used to generate code is totally customizable. This allows you to replace the default code generator and use another built-in code generator or create your own code generator that can read the model and generate code. Visual Studio 2010 comes with a few alternative code generators for your ADO.NET Entity Framework Model. If, for example, you want to customize the code that is generated for your entities you can right click the designer and choose the option Add Code Generation Item. This will turn off the default code generator and will allow you to pick a code generator you want to use for your model. The main advantage of using an alternate code generator is to suit different types of applications. For example by default the generate code for entities contains a lot of reference to ADO.NET Entity Framework. If you want to work with entities that do not have any reference to ADO.NET Entity Framework specific types, you can use the ADO.NET POCO Entity Generator as the code generator for your model. Once you pick a code generator, it will add a T4 template file with the extension of .tt. This T4 template file will read the contents of your model and generate code for your entities and the context object. You can open the T4 template in Visual Studio.NET and alter it to change the code that is generated. Handcrafted codeThe other option is to totally turn off the code generator and create your own entities and context. To turn off code generation you can set the Code Generation Strategy property of your ADO.NET Entity Framework Model to None. ADO.NET Entity Framework 4 has made the process of writing code for entities and the context much simpler. So let's go ahead and turn off code generation and create the classes required. The first step is to create some simple classes to represent our entities. public class Project{ public Project() { Tasks=new List<Task>(); } public int Id { get; set; } public string Name { get; set; } public List<Task> Tasks { get; set; }} public class Task{ public int Id { get; set; } public string Description { get; set; } public Project Project { get; set; }} public class CriticalTask:Task{ public DateTime DueBy { get; set; }} The above entities do not have anything specific to ADO.NET Entity Framework and are plain C# classes. Next we can create the context to expose sets of our entities, so that we can use it to updates and reads against our database. public class MyContext : ObjectContext{ public MyContext() : base("name=ToDoContainer", "ToDoContainer") { } public MyContext(EntityConnection connection) : base(connection) { } public ObjectSet<Project> Projects { get { return CreateObjectSet<Project>(); } } public ObjectSet<Task> Tasks { get { return CreateObjectSet<Task>(); } }} The above context uses the CreateObjectSet method to expose the collection of our entities as object sets. This allows you to use the context to CRUD operations on the database through the object sets. Handcrafted code is beneficial when you want to take control of your business entities, or you start your application development with the business entities in mind. Maybe the persistence for your business entities is not decided yet and you want to focus on the business logic. When you write code for entities and context, you will still need a model as represented in the ADO.NET Entity Framework Model, so any changes you make to either the model or the code will not be synchronized. One solution is to avoid representing the model in XML and, instead, move to a code-first approach: We'll describe this in the next section. Representing the Model - XML or CodeYou can choose how to represent the model metadata in your data access layer: whether you opt to use the ADO.NET Entity Framework Model as XML or whether you use code. The new ADO.NET Entity Framework provides a Code-first approach that allows you to map your entities to the data store using code expressions. XML FileIf you recall, the ADO.NET Entity Framework Model is just a simple XML file with an extension of .edmx. This file has three sections: the conceptual schema, the storage schema and the mapping schema. When you add an ADO.NET Entity Framework Model and create your entities in the designer, you are creating the XML file to represent the model. For example if you right click the model and open it using a XML editor you will see the content for the three schema files. The advantage with the XML file is the benefit that it can be opened in Visual Studio.NET and can make use of the ADO.NET Entity Framework Model designer. 'Code First''Code first' augments the approach of writing code for your entities and context. This approach allows you to map your entities to the data store using code instead of using a model file. This also avoids the problem you would face of keeping your model synchronized with your entities when not relying on code generation. When you use 'code first', you do not need an ADO.NET Entity Framework Model file (.edmx) One main advantage of 'Code First' is it makes it easy to test your mappings. You do not need to rely on XML files. 'Code First' also makes it easy to read and understand the mappings compared to looking at XML files. Before we start, we need to add a reference to Microsoft.Data.Entity.Ctp assembly file. Then let's create code to specify the mappings for the handcrafted entities and context we created earlier. var builder = new ContextBuilder<MyContext>();builder.Entity<Project>().Property(p => p.Id).IsIdentity();builder.Entity<Project>().HasKey(p => p.Id);builder.Entity<Task>().Property(p => p.Id).IsIdentity();builder.Entity<Task>().MapHierarchy( c => new {c.Id, c.Description, Project_Id = EntityMap.Related<Project>(p => p.Tasks).Id}).ToTable("Tasks");builder.Entity<CriticalTask>().MapHierarchy(c => new {c.Id, c.DueBy}). ToTable("Tasks_CriticalTask"); In the above code we use a class called ContextBuilder to configure our entities and specify how they map to the database tables. To configure the Project entity we specify that the Id property is an identity column and that it is the key for the Project entity. Next we map the Task entity and specify the Id property as an identity and a key for the Task entity. We also specify that there is a hierarchy for the Task entity and specify the columns in the Tasks tables. We explicitly map the Project_Id column as being related to the Project Entity. Similarly we also map the CriticalTask entity to the Tasks_CriticalTask table. Now you can create the context using the ContextBuilder instance and point it to your database using a database connection and perform your CRUD operations. var connection = new SqlConnection( "Data Source=.;Initial Catalog=TaskDb;Integrated Security=True;MultipleActiveResultSets=True");using (var ctx = builder.Create(connection)){ //CRUD operations} Summary This article looks at different decisions you will take when developing your data access layer using ADO.NET Entity Framework 4.0 and the range of options available to you. It also introduces some of the new features that are part of ADO.NET Entity Framework 4.0. |
Think something needs changing?
If you've spotted something that needs update or review, please let us know by reaching out to the editor.
Load comments