|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionEnterprise 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 properies 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! Finally, to leverage inheritance, we would see how just a single 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:
Despite five different product types (four concrete, and one abstract), and a need to display/update items belonging to only one of the product type; the most interesting part of this code is a complete absence of any of BackgroundWhen 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# solutions 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:
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. 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. Certain columns only make sense within the context of a specific product type. For example, while analyzing
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 ReviewLet 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 Using the EF Generated Class HierarchySo 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.
After the classes were auto-generated by the EF, we manually added a 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 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 first line of this method is a 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
Its first line is exactly the same as the one described in 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 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. 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 //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 OutputFollowing is the program output. You may want to compare it with the ****** 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
Points of Interest/CreditsAlthough 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.
|
||||||||||||||||||||||