Following is an edited excerpt from Julia Lerman's book, Programming Entity Framework, Second Edition (O'Reilly Media). The excerpt comes from Chapter 18: Using POCO Entities and Self-Tracking Entities in WCF Services.
A common approach to building services in .NET 3.5 was to use Data Transfer Objects (DTOs) to carry an object's data between the client and the service. This approach provided some benefits, but converting the EntityObjects to DTOs and back again was time consuming. However, now that EF supports POCO classes, the need for using DTOs to carry an object's data between the client and the service is greatly reduced. You can do away with DTOs completely if you want, although your architecture may require them for different reasons unrelated to the EF. Without the EntityObject, the message is much smaller and much less complex, and you can use your code-generation template to inject state properties into your classes.
In addition to using your own Plain Old CLR Objects (POCO) classes in WCF services, Microsoft provides a specialized POCO template that creates what are called self-tracking entities. This template creates enhanced POCO objects, which include state properties and some other specialized interfaces and functionality that allow state information to easily move between the client and the server without the author of either the service or the client application having to work out the logic of maintaining state information. In this article, I'll explain how to create POCO classes based on a model, apply some enhancements to these POCO classes to make them friendlier for use in WCF services, then build a service that makes use of these POCO classes.
Creating WCF-Friendly POCO Classes
Before creating the services, you'll need an appropriate set of POCO classes to work with. Therefore, in this section you will walk through the following tasks:
- You'll build a model based on a sample database, then switch its code generation to use a Microsoft-created code-generation template that builds POCO classes rather than EntityObjects.
- You'll create a simple base class to provide state information to the entities and modify the T4 template so that the entities automatically inherit from that class.
- You'll modify the T4 template one more time to remove the virtual keywords from the generated entity properties. This will prevent EF from creating dynamic proxies at runtime, helping you to avoid problems as entities are being serialized as they're sent from the service to the client.
Creating a model from the sample BreakAway database. To get to the fun part, you're going to have to fast forward through the creation of the model and its T4 template. The sample database is included in the sample code for this article, which you can download at the Programming Entity Framework downloads page.
In a .NET Class Library Project, create a new ADO.NET Entity Data Model pointing to this database and bring in all of the database's tables. You'll end up with a model that contains Contact, Customer, Reservation, Trip and Destination entities. In the book, readers will have modified the model to make Customer inherit from Contact. I won't have you bother with that for the sake of this article, but be prepared to see a few references to this inheritance as you read on.
Once the model is created, add a code-generation item using the ADO.NET C# or VB POCO template that you can install via the Visual Studio 2010 Extension manager. An additional step in the book walks through ensuring that the POCO classes are in their own project, which is better architecture, but not critical to what follows in this article.
Adding custom logic to the POCO entities with a base class. The next step for preparing your entities for WCF involves providing them with some critical functionality. One of the biggest challenges when working with entities across processes is the loss of state information. In Chapter 17, you created explicit operations for inserting, updating, and deleting customers. For handling the reservations attached to a customer, you had to make assumptions regarding whether a reservation was new by checking if the ReservationID was equal to 0 (new) or was greater than 0 (existing). Then, to handle deleted reservations, you created a somewhat kludgey solution by forcing the consumer to pass in a collection of the ReservationID values of each reservation to be deleted.