Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

Modeling Enterprise Applications with Entity Framework

4.09/5 (17 votes)
14 Aug 2008CPOL11 min read 1   739  
An article on leveraging Entity Framework to create a set of inherited business objects from a single table. Writing code without any conditionals!

Introduction

Enterprise Applications are architected with the division of responsibilities between different teams of IT professionals, developers, and data base administrators. Despite a very diverse need of information from different application perspectives, data integrity is something which no one would want to compromise. Since data is shared by many applications, no single application programmer has the luxury to modify the shared database schemas according a single application's needs; instead, he/she is supposed to write down the data access layer on top of existing schema to match the application needs with pre-existing database schema.

With the introduction of Entity Framework (EF), it has become very easy to model OO designs on top of any database schema. We would explore a very interesting example where the entire application is modeled visually using the EF designer. A set of classes (with inheritance) were automatically generated by the EF designer without having to write down any single line of code in C#, VB, or even XML. For that specific activity, no knowledge of XML, or SQL was needed -- just clicking, selecting, and specifying the object properties corresponding to table columns in a friendly UI was good enough.

Once the classes were auto-generated; the data was fetched by a simple single-line LINQ statement; which would then create the appropriately typed objects (instances of those classes) corresponding to each row; to-the-point (loaded with only the properties columns relevant to that specific type), and ready to go!
We would also draw interesting parallels between layers of this application and the famous MVC architecture.

Finally, to leverage inheritance, we would see how just a single display() method (per concrete class) is sufficient to render the most accurate formatting (of course that would in turn leverage from the same method in the base class before rendering the specific data of its own class).

Enterprise Needs: The ultimate goal of this hypothetical exercise is to fulfill the top management's need of adjusting prices of certain product groups according to inflation caused by high fuel prices and consequential rise in transportation costs; and still put seasonal goods on clearance sale -- summer is quickly coming to an end!

We will try to:

  • Eliminate coupling (through EF)
  • Reduce duplications using inheritance/polymorphism
  • Increase cohesion by putting similar methods right next to each other in separate C# files

Despite five different product types (four concrete, and one abstract), and a need to display/update items belonging to only one of the product types; the most interesting part of this code is a complete absence of any of if, else, switch, case statements in C#; and any LINQ/SQL where clauses (in manually written code). That way, we have completely eliminated code duplication, and achieved a higher degree of cohesion.

Background

When I first heard of Entity Framework, I tried to look for some examples in Code Project, but couldn’t find one that implements an inheritance hierarchy on top of a single table. So I decided to write a simple C# solution that would be directly usable in Visual Studio 2008 SP1.

In this particular example, we have a single SQL Server table containing several products classified into different types (based on whether they are seasonal or are discontinued). Following four “product type codes” were assigned: 00 for Regular products; 01 for seasonal; 10 for discontinued; and 11 for seasonal, but discontinued. Following is the “Product” table:

LinqEntityFramework/ProductTable.png

Note that in an actual application, there may be thousands of records for each product type (category). However, for the sake of simplicity, only five have been picked up in this example. Although for data performance efficiency, the two character coding system is great; yet if we literally use these cryptic codes in our program, it would be very confusing/hard to remember what code is used for which type. So it was decided to use the friendlier names instead of code, i.e., RegularProduct, DiscontinuedProduct, SeasonalProduct, and SeasonalDiscontinuedProduct; instead of binary coded 00, 01, 10, and 11 (for the sake of brevity, let us start calling them “entity names” or “class name” depending on whether they are called from the EF designer, or VB/C# program code).

We have decided to do all those mappings using Entity Framework. That way, any person even without any knowledge of VB, C#, XML, or SQL language could maintain and extend the mappings.

We have four concrete product types, so we would create the four entity names corresponding to each one of them. That way, in our application code, we would just use the class name (e.g., SeaonalProduct) to fetch out records corresponding to ProductType 10). How about fetching of all records in the Product table? It would be better if we create yet another class which does not filter rows specific to any of the four conditions. We would call it Product. We would map ProductID, Name, and Price into the Product entity class; and derive rest of the four concrete classes from it. That way, we would inherit those three fields that are needed (are of common interest) in all of the derived classes, and would not have to unnecessarily duplicate them (into all four of them).

Certain columns only make sense within the context of a specific product type. For example, while analyzing DiscontinuedProduct, we would like to know when they were discontinued; similarly for SeasonalProduct, we are supposed to keep records of much off season discount we are planning to give. Therefore, in addition to setting the “When” condition for product type codes, we would also map those additional columns to properties of our entity class. Using the EF designer, we can do all the mappings visually, without having to write a single line of C#/VB/XML code.

LinqEntityFramework/EntityDiagram.png

Figure 1

The entity “DiscontinueProduct” maps to the Product (table) When ProductType = 01. It also has the "DisconinuedDate" property, which is mapped to the DiscontinuedDate column.

Mapping Review

Let us review what we have done so far – using VS 2008 EF designer, we have automatically generated Objects, which Map to a Relational database table(ORM). All five entity classes map to a single table, filtering rows according to the condition specified in “When”. This frees us from writing SQL where clauses, or sprinkling if/switch/case statements throughout our program (making it hard to read/relate/maintain).

The program would be written without a need to have an intimate knowledge of underling database schema. In fact, the compiled program is completely isolated from any knowledge of database, its schema, its location, SQL dialect; or even database brand (besides SQL Server, it could be Oracle, DB2 or any vendor whose EF provider has been developed).

The only mention of a database connection is in App.Config file which could be altered with recompiling of source code. The only one place where database tables are coupled (mapped) with objects is through the UI of “Entity Designer”. The C# code is free of any reference to the usual Connection, Command, DataSet, DataReader, or any other ADO.NET class. (To get the view of Figure 1, please double click on “TablePerHierarchy.edmx, and then view the mapping of each entity by clicking on them one by one)”.

Using the EF Generated Class Hierarchy

So far, we did not write a single line of code, and the EF automatically created several entity classes behind the scenes. If we open the class diagram "EFHierarchy.cd", we would find the EF generated classes.

LinqEntityFramework/ClassDiagram.png

After the classes were auto-generated by the EF, we manually added a Display() method; and a ProductType property in all of the five classes. To take advantage of polymorphism, we declared both the property and method virtual in Product base class; and override them in all four derived classes. This hierarchy of these five classes is accessed (by its consumers) through the TablePerHierarchyContainer. Shouldn't we call it a "Model"?

Operations on the "Model"

The Operations.cs contains the code with two basic operations on the Model (MVC enthusiasts like to understand software in terms of Model, View, and Controller layers). In this implementation, we would also attempt to draw some parallels from that architecture. It (the Operations.cs file) was used to extend the EF generated partial class TablePerHierarchyContainer by enriching it with two operations (generic methods): Display<ProductType>() and ChangeByPercentagePriceOf<ProductType>(), which takes Product as an argument. Since Product is the base class of this hierarchy, we can pass any one of these 5 classes as an argument to these methods, depending on whether we want to have the operations done on all rows of Product table, or just on the ones which belong to a particular product type (category) in our inventory.

C#
public void Display<ProductType>() where ProductType : Product {            
    foreach (Product product in (
        from product in Products.OfType<producttype />() select product)) {
        //Display products using the appropriate Display methods of one of the
        //four implementing classes
        product.Display(); Console.WriteLine();
    }
}
        public void ChangeByPercentagePriceOf<ProductType>(
            Decimal percent) where ProductType : Product {
            foreach (Product product in (
                from product in Products.OfType<producttype />() select product)) {
                //Update price using the "Price" property implemented in base
                //"Product" class
                product.Price += product.Price * percent / 100;
            }
            SaveChanges(true);
        }

In both operations, only a single line of LINQ statement iterates though the entire collection of products.

  • The "Display" Operation

The first line of this method is a foreach statement (with embedded LINQ block). It fetches all of the Product table rows, and renders them as instances of one of the four concrete classes (using the base class reference). That way, we can call the polymorphic Display() method in the subsequent statement to get the table rows, displayed by one of the four derived classes, handling the specific properties of a given Product Type (passed as an argument to this generic method).

C#
foreach (Product product in (
        from product in Products.OfType<ProductType>() select product)) {
         //Display products using the appropriate Display methods from one of the
         //four implementing classes
    product.Display();Console.WriteLine();
}

We would carry out the analysis of product.Dispaly() method in the View section.

  • The "Change By Percentage, price of" Operation

Its first line is exactly the same as the one described in Display operation above. In the second line, it adds the percentage of increase in a product's price, and once it is done updating prices of all products; it saves the changes.

C#
foreach (Product product in (
    from product in Products.OfType<ProductType>() select product)) {
    //Update price using the "Price" property implemented in base "Product" class
    product.Price += product.Price * percent / 100;
}
SaveChanges(true);

Rendering the "View"

The DisplayFormatting.cs contains partial classes for the display of model data. They accomplish a very simple View of our EF generated Model. They just dump their fields using the Console.Write statement. For example, the base class displays Product ID along with thee other properties common in all five classes:

C#
public virtual void Display() { Console.Write("{0}:{1}: {2}\t {3:$###.00}",
    ProductID, ProductType, Name, Price); }

The Seasonal product first calls the base class to do display the regular product fields, afterwards, it also writes the off season discount.

C#
public override void Display() { base.Display(); Console.Write(
   "; Discount {0:##.00}%", OffSeasonDiscount); }

I don't think we need any further explanation for other concrete classes for our smart readers, as they are just one line methods with an identical purpose. The only thing special about them is that they are written encapsulated within their specific product type classes, hence they contain reference to the fields which are exclusively available in their own scope.

Implementing Business Application through "Controller"

The entire "Business Application" is written in a single MainProgram.cs. The Main program is a sequence of one line calls to the operations of "Model" (we just have display, and price change). If you really want to designate some part of this application as a "Controller" of MVC, it is this sequence. The executable calls the operations on "Model" passing different product types. I have added lot of comments to make its purpose obvious.

The only point I want to make is that this could be written by a team of developers who just know the enterprise business needs, and how to activate the two operations of the Model. They just pass one of the Product types to get to the right set of rows from the Product table, and optionally a percentage figure to adjust to cost. I have stripped of all fancy things to keep it very simple to understand by even the beginners.

C#
//CODED BY APPLICATION PROGRAMMERS

//Auditors want the entire inventory displayed, with all possible
//specifics -- irrespective of items' product classinfaction
Console.WriteLine("****** FIRST DISPLAY THE ENTIRE PRODUCT IN INVENTORY ***");
ef.Display<Product>();

//Finance Department is worried about increasing fuel cost. 
//In an email, they asked us to raise regular item price by 2% to cover the
//transportation expenses
Console.WriteLine(
    "\n\n****** INFLATION! -- INCREASE PRICE OF THE REGULAR PRODUCTS BY 2%***");
//Change price of "Regular Products" by 2 percent
ef.ChangeByPercentagePriceOf<RegularProduct>(2);
Console.WriteLine("\n\n****** NEW PRICE OF THE REGULAR PRODUCTS After 2% INCREASE***");
ef.Display<RegularProduct>();

//Marketing Department is worried about low sales. They want to sell everything which
//would die in next 15 days.
Console.WriteLine(
  "\n\n****** CLEARANCE SALE! -- REDUCE PRICE OF THE SEASONAL PRODUCTS BY ANOTHER 40%***");
//Change price of "Regular Products" by -40 percent
ef.ChangeByPercentagePriceOf<SeasonalProduct>(-40);
Console.WriteLine("\n\n****** NEW PRICE OF THE SEASONAL PRODUCTS After 40% DISCOUNT***");
ef.Display<SeasonalProduct>();

Program Output

Following is the program output. You may want to compare it with the Product table contents, the first illustration in the Background section.

  ****** FIRST DISPLAY THE ENTIRE PRODUCT IN INVENTORY ***
1:RegularProduct: Nail Box       $5.09
2:DiscontinuedProduct: Bubble level      $5.99; Since 02/02/07
3:SeasonalProduct: Flowers       $9.07; Discount 40.00%
4:SeasonalDiscontinuedProduct: Roses     $12.00; Discount 50.00%, Since 04/02/07

5:RegularProduct: Nuts and Bolts         $3.18


****** INFLATION! -- INCREASE PRICE OF THE REGULAR PRODUCTS BY 2%***


****** NEW PRICE OF THE REGULAR PRODUCTS After 2% INCREASE***
1:RegularProduct: Nail Box       $5.19
5:RegularProduct: Nuts and Bolts         $3.24


****** CLEARANCE SALE! -- REDUCE PRICE OF THE SEASONAL PRODUCTS BY ANOTHER 40%**



****** NEW PRICE OF THE SEASONAL PRODUCTS After 40% DISCOUNT***
3:SeasonalProduct: Flowers       $5.44; Discount 40.00%

Using the Code

  1. First, the database EFHierarchy containing table Product needs to be created. To do this, from SQL Server 2005 Management Studio, open the file (File->Open->File) , and select CreateEFHierarchyDB.sql, and press the Open button.
    Please edit the default "C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA" path if you want to create the database at another location. Press the execute button.
  2. After refreshing the view so that you see the EFHierarchy database, open the empty table Product. Now open the Excel sheet EFHierarchy.xls, and select its rows 2 through 6, copy and paste them into blank table Product. Make sure you press the execute button to fill data into table.
  3. Unzip BusinessApplication.zip into a place where you would want to extract project files.
  4. Upgrade your Visual Studio 2008 with SP1 Visual Studio 2008 Service Pack 1 (SP1) and .NET Framework 3.5 SP1 Downloads are now available for download from MSDN.
  5. Open the BusinessApplication.sln (File-> Open -> Project/Solution), build and run.
  6. Each time you will run the project, the regular products (item #1 and 5) will keep on becoming more and more expensive (by 2% each time); and seasonal products would lose their value by 40%

Points of Interest/Credits

Although we started with a single table, the application of Object Oriented principals through the friendly EF designer of the Visual Studio made it possible to write down a pretty involved application with a minimum of hand written code. The splitting of application into three source file/ two assemblies was purposely done so that they are potentially owned/checked in/packaged by different teams of varying skills set/responsibilities. The example in this article was based upon the article of Erick Thompson, ADO.NET team blog. The architectural philosophy is deeply influenced by the teachings of Martin Fowler and Robert C. Martin.

I recently discovered a great tool for advanced modeling. My special thanks for Diego Vega of Microsoft, who pointed me towards this very useful resource while answering my question in ADO.NET Entity Framework and LINQ to Entities (Pre-release) forum. I recommend the readers to download the simple, but exciting Entity Framework Mapping Helper v1.0.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)