Tuesday, April 12, 2011

Programming with Entity Framework using DDD and
LINQ/Lambda expressions using LINQPad 4

I always like to keep my mind busy with quite a few small software tasks while watching a movie or IPL cricket match and having a sip from a glass full of hot almond chocolate milk. Last week I had got the chance to see the T20 match between Pune Warriors India and Kings XI Punjab while thinking about LINQ and Lambda expression in C#. I completed the coding and subsequent write up faster before completing my chocolate milk analogous to how cricketers compete in T20 matches. The write up is based on the extension of the methodology of developing N-tier database applications which follows Domain Driven Design approach a.k.a. DDD. Though this approach does not replace the conventional methodology of writing database applications wherein the design generally starts with database table design and goes up till the user interface but it gives a more obvious way of realizing the model entities and their associations in the applications from the application perspective.

Domain model is the heart of DDD. Model defines the domain entities and their associations which constitutes the application and eventually defines the structure of the database/data store which is more or less same as the application class diagram. This mapping is known as ORM (Object-Relational mapping). It can be understood as follows:

C#
Database
Class
Table, Procedure, View
Field/Property
Column
Property of associated class a.k.a. Navigation propeties
Tables linked with the referential integrity – foreign keys

The use of ORM also reduces the developer’s burden of writing stored procedures for operating on the database. The tools that are most commonly used for ORM are NHibernate (available from the open source community) and Entity Framework (VS.NET). The ORM and LINQ (Language Integrated Query) serves as a basic framework for achieving the CRUD operations in any application. It is often experienced that an application may fail or tend to fail when its domain model is not prepared as it exists in a real time scenario. There may be the case when an architect and a developer together have to spend extra efforts at the later stage of application development life-cycle to stabilize the application as a whole. There are many articles available on internet which explains DDD in greater details. Lets keep it short and simple for the scope of this write up. A typical application which follows DDD pattern has following layers in it:

Finders and repositories:

These are the set of classes which are specific to each entity in the application that executes the search for an entity. It contains as many functions as possible which can able to search entities in all the possible ways with all the possible parameters. E.g. A ProductFinder class can have the functions like GetProductByID() and GetProductByName() to fetch the products based on ID and Name respectively.

Services:

These are the set of classes which helps to expose the functionality to different client application. It should not be confused with a WCF service or a web service which has several endpoints. Instead, the service, in this context is a wrapper for all the DML operations of the application. This can be visualized as the application layer which resides on the top of the repositories and finders. Lets take the reference of the domain model as below and have a brief look at the EF.



How to read the above diagram:

There are 5 entities in the application called CustomerDemographic, Customer, Order, Shipper and Order_Detail. All the entities have their respective tables in the database with each of the field/property mapped to its respective column. The referential constraint for the associations can be understood as follows:

Customer -> Order:
One customer can have many orders.
One order may or may not be associated to a customer

Order -> Order_Detail:
One order can have many order details.
One order detail can be associated to only one order

CustomerDemographic -> Customer:
One customer can have many customer demographics associated
One customer demographic can be associated with many customers

Navigation properties:

The navigation properties aka association path sets the relationship between the entities. The association path can be the property inside a C# class which is of the same type as the associated class. The association can be one-to-one (property of the type class) or one-to-many (property of the type List). The navigation properties can also be visualized as the referential integrity used to create table joins in the SQL.

Programming CRUD operations with EF:

a) Create:
private void CreateProduct()
{
var product = new Product();
// Set the properties and associated entities related to this product entity
product.ProductName = "Product 1";
// The associated entities could be a new instance or the existing ones which are fetched separately from the database
product.Category = new Category() {CategoryName = "Category 1", Description = "Test Category"};
product.Supplier = new Supplier() {Address = "Address 1", City = "City 1", CompanyName = "Company 1"};
// Save to the database and commit the changes
northwindEntities.AddToProducts(product);
northwindEntities.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
}

b) Read
private List<string> GetSpecificContacts()
{
// Get the ContactName of all the Customer whose Order is Shipped by "Speedy Express"
var customerNames = (from shipper in northwindEntities.Shippers
from orders in shipper.Orders
join customer in northwindEntities.Customers on orders.Customer equals customer
where shipper.CompanyName == "Speedy Express"
select customer.ContactName).Distinct().ToList();
// Lambda expressions
var customerNamesFromLambda = northwindEntities.Shippers
.SelectMany(
shipper => northwindEntities.Orders,
(shipper, orders) =>
new
{
shipper = shipper,
orders = orders })
.Join(
northwindEntities.Customers,
temp0 => temp0.orders.Customer,
customer => customer,
(temp0, customer) =>
new
{
temp0 = temp0,
customer = customer })
.Where(temp1 => (temp1.temp0.shipper.CompanyName == "Speedy Express"))
.Select(temp1 => temp1.customer.ContactName)
.Distinct();

return customerNames;
}

c) Update:
private bool UpdateProductByName()
{
var product = northwindEntities.Products.Where(a => a.ProductName == "Product 1").FirstOrDefault();
product.ProductName = "Product 1 Updated";
northwindEntities.SaveChanges();
return true;
}

d) Delete:
private bool DeleteProduct()
{
var product = northwindEntities.Products.Where(a => a.ProductName == "Product 1 Updated").FirstOrDefault();
northwindEntities.Products.DeleteObject(product);
return northwindEntities.SaveChanges() > 0;
}

LINQ – No more round-trips to database:

LINQ is the language feature with which the developer can query the collection analogous to the database queries. This feature came into existence with the increasing demand of performing database look-a-like operations on the in-memory cached data.

Using LINQPad;

LINQPad is the free tool which helps the C# developer to write and test LINQ queries. It helps the developer to convert LINQ to Lambda expressions and Lambda expressions to LINQ queries. It also helps a developer to see the SQL statement that equivalents the LINQ/Lambda expressions. There are other features which may seem irrelevant for a developer while working on line-of-business applications. The screenshot of LINQPad at work is shown below:


Figure 1


Figure 2

Enjoy what you do, do what you enjoy!
Stay tuned, stay connected!

No comments: