The Entity Framework In Layered Architectures
This column is based on a prerelease version of the ADO.NET EntityFramework. All information herein is subject to change.When architects of an n-tiered architecture evaluate any new technology, pattern, or strategy, they have to consider how that new piece of the puzzle is going to mesh with the architecture. With the Entity Framework, integration is not a problem. It can be integrated into an n-tier architecture as well as a single-tier architecture.In this month’s column I will demonstrate how the Entity Framework can fit into an n-tier architecture that uses Windows® Communication Foundation (WCF) and Windows Presentation Foundation (WPF) technologies and the Model View Presenter (MVP) pattern. I will present a sample architecture that contains layers for a logical store database, data access, a domain model, a business manager, a service layer, a presentation layer, and a passive UI layer, and I will demonstrate how these layers integrate using the Entity Framework. All of the code examples I use are available for download from the MSDN® Magazine Web site.Defining LayersThe application I’ll present allows a user to search for customers in the NorthwindEF sample database and view, add, edit, or delete them. Before diving into the code and the examples, let’s discuss the overall architecture of the sample. Because my focus is not the architecture itself, but how to integrate the Entity Framework with an architectural design, I chose a relatively common architecture that can be modified and integrated fairly easily with other strategies. Figure 1 shows a high-level view of a typical layered architecture. The top two layers handle the user interface presentation and navigation using a UI layer and a presentation layer. The UI layer can be implemented in any one of a variety of technologies; however, for this column and its examples I will use WPF. The UI layer follows the MVP pattern with a passive view, which means that the views (the top UI layer) are managed and directed by the presentation layer. The presenters are responsible for giving the views their data, pulling data from the views to be saved in the lower layers, and in general for responding to events raised by the views. Figure 1 Architectural Overview (Click the image for a larger view)The presenters communicate with the lower tiers through WCF in my example here. A presenter will invoke a service through WCF using the service’s contract as a guide. The service layer exposes its services through service contract interfaces. These contracts allow the presenters to be certain of how to call the services. The service layer is responsible for receiving the communications from the presenters and calling the appropriate business layer methods that will execute appropriate business logic and data gathering or modifications. The business layer is where the business logic and the LINQ to Entities code for this project would reside. The LINQ to Entities code will reference the entity model that is generated from the Entity Framework. When the LINQ queries are executed, the Entity Framework will translate the LINQ query to the conceptual entity model (the Entity Data Model, or EDM), map the entity aspects to the storage layer, and generate a SQL query to execute against the database.Building the ModelNow that I’ve provided a high-level overview of how the layers work in the architecture, let’s examine the key aspects of each layer as they pertain to the Entity Framework. Since the database already exists for the application, I generated the entity model from the NorthwindEF database as a starting point.I could have built the entity model first and then mapped the entities to the database as well. The EDM wizard helps generate the base entity model, which can then be modified as needed to incorporate inheritance, entity splitting, and other domain modeling concepts. Figure 2 shows the EDM wizard with all tables and stored procedures selected to be imported into the EDM.
Figure 2 Generating the Model from the Database (Click the image for a larger view)One topic that often causes people confusion in regard to EDMs is the default naming convention for the EntitySets and the EntityTypes. I like to use singular names for all of my entities in my domain models. I create an instance of a Customer or return a list of Order instances using List
Figure 3 Changing the EntityType Names (Click the image for a larger view)How It WorksNow I will demonstrate the application and discuss how it operates from the top layer down, starting with the views (located in the NWUI project) and the presenters (located in the NWPresentation project). Both projects are available in the code download that accompanies this column. The application loads a customer search view, which allows the user to search for customers by matching the company name criteria (see Figure 4). The view is implemented using WPF, and when a user interacts with the view it raises events that are listened to by its presenter, who can then take appropriate action.
Figure 4 Searching for Customers (Click the image for a larger view)When the user searches for all customers starting with the letter D, as shown in Figure 4, the view raises an event when the user clicks the Search button. The presenter listens for this event and responds by calling the service layer through WCF to get the list of customer entities that will be displayed on the CustomerSearchView. Here is the code in the view when the user clicks the Search button:private void btnSearch_Click(object sender, RoutedEventArgs e) { if (FindCustomerSearchResults != null) FindCustomerSearchResults(); }This code does not interact with the list of entities that are returned, but, rather, it leaves that up to the presenter. The view uses WPF data binding to reference the entity’s properties so it knows how to bind the list of entities to the list view control’s elements. The only interaction the views have with the entities is through the data binding.The CustomerSearchView raises the event FindCustomerSearchResults, and the CustomerSearchPresenter listens for the event and responds by taking the baton and performing the search. The following code shows how the CustomerSearchPresenter class creates an instance of the NWServiceClient class, which is a proxy to the WCF service that is exposed on the lower tier: public void view_FindCustomerSearchResults(){ if (this.view.CompanyNameCriteria.Length > 0) using (var svc = new NWServiceClient()) { IList
Figure 5 Editing Customers (Click the image for a larger view)When a user makes a modification to the customer and saves it, the entity is passed to the lower layers from the presenter using the code shown in Figure 6. This code evaluates whether the user was adding or modifying a customer and then calls the appropriate service layer method, passing the entity along for the ride.The service layer will then pass control on to the business layer, which will then save the customer entity to the database. Since the customer entity is no longer part of an ObjectContext, it must first be reunited with one by using the ObjectContext’s Attach method, as shown in the code shown below. Once the entity has been attached to the context, the entity’s properties must be marked as modified. This can be done by using the context’s ObjectStateManager and invoking the SetModified method for each property. Now that the context knows the entity is modified, the SaveChanges method can be issued, which will then generate a SQL UPDATE command and execute it against the database:public void UpdateCustomer(Customer customer){ context.Attach(customer); customer.SetAllModified(context); // custom extension method context.SaveChanges();}Notice that the code in the UpdateCustomer method uses an extension method I named SetAllModified
Figure 7 OptimisticConcurrencyException (Click the image for a larger view)You can trap this exception and take whatever action is appropriate. For example, you could trap the exception, log it, and then overwrite the user’s changes anyway, as shown here:catch (OptimisticConcurrencyException e){ context.Refresh(RefreshMode.ClientWins, customer); // Last in wins logger.Write(e); context.SaveChanges();}Deleting and AddingWhen a user deletes a customer, the CustomerManager’s DeleteCustomer method gets the customer entity and applies the delete: context.Attach(customer);context.DeleteObject(customer);context.SaveChanges();First, the Customer entity instance must be reunited with an ObjectContext using the Attach method. Then the customer must be deleted from the ObjectContext. Done this way, the change tracking mechanism within the ObjectContext is aware the Customer entity instance has been deleted. Finally, when the SaveChanges method is called, the ObjectContext is now aware the entity was deleted and it should generate a DELETE SQL command and execute it.When adding a customer, the CustomerManager’s AddCustomer method gets the customer entity and applies the insert, like so: context.AddToCustomers(customer);context.SaveChanges();This entity instance is new, so it must be added to the context and flagged as a new instance of a Customer entity by associating the Customer entity instance with an ObjectContext using the AddToCustomer method. Finally, when the SaveChanges method is called, the ObjectContext is aware that the entity was added and that it should generate an INSERT SQL command and execute it.Wrapping It UpHere I’ve demonstrated how the Entity Framework can integrate into an architecture, use modern patterns such as the MVP pattern, and handle the common architectural concerns. Key components of the Entity Framework in layered architectures are its change tracking mechanisms, integration with LINQ to Entities, ability to disconnect and reconnect with its ObjectContext, and how it provides a means for a developer to handle concurrency issues.
John Papa (johnpapa.net) is a Senior Consultant with ASPSOFT (aspsoft.com) and a baseball fan who spends summer nights rooting for the Yankees with his family. John, a C# MVP and INETA speaker, has authored several books and is now working on his latest, titled Data Access with Silverlight 2. He often speaks at conferences such as DevConnections and VSLive.
↧
Data Points: The Entity Framework in Layered Architectures
↧