Business Logic with Entity Framework

This article I posted on Code Project please enjoy it and don’t forget to share your comments.

Introduction

In this article I’m going to demonstrate how you can use Entity framework to do some basic logic when a change happens in related entities or “Associations” as it is called. And to keep it simple I’m going to illustrate an update of an Order’s Total Amount when its Order Details get changed, Added or deleted.

Background

Well, some developers love to stick to what they know to solve every problem just as the old saying “when you have a hammer, everything looks like a nail to you” but for me I’d like to explore new stuff and know the difference.

First of all I’d like to give you an idea of the possible alternatives that we have to solve this problem and their challenges:

1. Using Database Triggers on the child table to update the parent table.
Challenges:

  • You will do the calculations on the UI while the user is updating the DATA and once again when issuing the update or change back to the database and that’s duplicate work.
  • Your application will not get notified of the change if it was done on the database unless you are using a database engine that has some mechanism of notification.
  • You don’t know much SQL or vendor-specific language or extensions to implement such triggers and all you’ve got is your IDE and programming language.

2. Use Database Views to do the calculation when needed to be shown to the user.
Challenges:

  • You will put most of your Business-Logic in the database and need a GOOD DB administrator to maintain your database performance and code.
  • The calculations only occur when the user requests to see the data and that could be problematic in some systems that need to maintain some logic on the changes of the calculation logic.
  • Again if you don’t know much of SQL or would like to stick to your IDE this is not the way to go unless you are willing to learn how to manage a Database the right way.

3. Use the solution provided here in this article by attaching your business logic to your entities.
Challenges:

  • You need to get some basic grasp on ORM techniques and a lot of OOP knowledge.
  • Your logic is now stuck with your client application or Data Access Code and that’s against N-Tier architecture.
  • Anything else you think is a problem? { it’s up to you to use your imagination }

Solution

Ok, now we have an idea of what is good and what is bad so let us go ahead and start learning our solution, To demonstrate our solution I’ve created a small database of two tables as you can see from the following diagram:

EntityFrameworkLogic2.png

So we have Orders and OrderItems and what we want to achieve here is that when the OrderItems of an order change by adding, deleting or updating we want to update the TotalAmount of the parent Order to reflect the sum of (Quantity x Price) of its child OrderItems.

And to make it even harder we want the calculation to include all the OrderItems that we have on our memory or cache and also any other OrderItem in the database that we didn’t have on memory when the update is initiated.

And let us start by creating our solution in visual studio, and in this case you will have to use VS 2008 with SP1 installed otherwise I’m not going to explain any alternatives.

I’ve created a new windows forms application called “EFLogicDemo“ and added a new ADO.NET Entity Data Model to it and named it “OrdersModel”.

EntityFrameworkLogic3.png

A wizard will ask you if you want to generate the Model from a database and that’s fine in our case because we are not going to do anything advanced or fancy so just direct the wizard to connect to our database that we created earlier and let it do the magic and don’t forget to let the wizard save our connection string in App.Config.

And as a tweak EF does not distinguish plural names like its old LINQ to SQL does, so I changed the default names for the “Entity Set Name” and “Name” for each of the generated entity to make it like the following:

1. SalesOrders

  • Entity Set Name = SalesOrders
  • Name = SalesOrder

2. OrderItems

  • Entity Set Name = OrderItems
  • Name = OrderItem

And here is how our Entity Model looks like after completed:

EntityFrameworkLogic4.png

Okay, now we are clear to give our coding skills a spin, right? We can start by adding a new class to our project and Call it exactly as the Parent Entity that we want to implement its logic, in our case SalesOrder as illustrated below:

EntityFrameworkLogic5.png

And make sure you change its access modifier to public partial in order to extend the existing class that EF generated for our entity.

Using the Code

Now we need a starting point, in this case we want to listen to the event AssociationChanged on our related child entity and the best place to do that is the constructor of the class as it makes sure our event listener will be called on any instance created inside our application, and here is the code to do so:

public SalesOrder(){ this.OrderItems.AssociationChanged +=     new CollectionChangeEventHandler(OrderItems_AssociationChanged);}

So far so good, we have a method called OrderItems_AssociationChanged that will be called when any changes happen on an OrderItem that is related to the current instance of SalesOrder and this method’s type has an argument of type System.ComponentModel.CollectionChangeEventArgs which give us two properties called Action and Element that tells us what happened and where.

Now in our method we get notified of changes that we need to act upon, so what I’m going to do is to Eagerly load all the details if possible from the database and then do the calculation on them and update our SalesOrder by the new calculated TotalAmount do just that I create a new method to do the calculation and called it UpdateTotalAmount and here is the code:

private void UpdateTotalAmount(){ // load all our OrderItems from the database if and ONLY if this SalesOrder // was saved in the database, otherwise the load will give an exception if (this.EntityState == System.Data.EntityState.Unchanged || this.EntityState == System.Data.EntityState.Modified) {     // while loading back database changes, we want to preserve any modification\     // that was made to our local instances     this.OrderItems.Load(System.Data.Objects.MergeOption.PreserveChanges); }

 // calculate the new TotalAmount if there is any OrderItems found in the collection var newAmount = OrderItems == null ? 0 : OrderItems.Sum(d => d.Quantity * d.UnitPrice);

 // apply the changes and update the current instance with the new value this.TotalAmount = newAmount - (this.Discount ?? 0);}

Well, the code is pretty easy and commented and really does not need more explanations.

Now all we need to do is to call this method in our event listener OrderItems_AssociationChanged but there is one more thing here before we go ahead, What if the OrderItem had its properties changed? What will happen?

Well, we are only monitoring the changes of the relationship or association and if the child entity got its property values changed we will never get notified UNLESS we listen to its changes and here is how it can be done using the Holy Interface of INotifyPropertyChanged all we need to do is to attach another listener to that event on every item of our collection for the event PropertyChanged and we get notified of any change that happened on our child elements, or even we go ahead and do some login on the child element class itself and it should be easier, but I chose to do it all in one place and here is the final code of our AssociationChanged:

private void OrderItems_AssociationChanged(object sender, System.ComponentModel.CollectionChangeEventArgs e){   // if a new SalesItem is beeing added to this SalesOrder   if (e.Action == CollectionChangeAction.Add)   {       var detail = (OrderItem)e.Element;      // attache some code when this SalesItem has its properties changed      // the following code uses Lambda expression and anonymous method syntax       detail.PropertyChanged += (s, a) =>       {           // now we are here invoked from the SalesItem that was changed and we have 2 parameters we can use           // (s) which is the insance of SalesItem that was changes           // (a) which is the arguments that will tell us what exactly did change           // now we only want to re-calculate if the Quantity or Unit price changed           if (a.PropertyName == "Quantity" || a.PropertyName == "UnitPrice")           {               // do the re-calculation               UpdateTotalAmount();           }       };   }        // we are called here by AssociationChanged and this means we need to recalculate too.   UpdateTotalAmount();}

Testing the solution

Now I can hear someone talking there about if it will work, and I reply: Unit Testing ;) because its fast, its easy and it needs no effort in designing anything fancy to start using your code, and I’ve developed this unit test to test most conditions that could happen to our Entities such as Adding, Deleting and Editing/Updating the Child Entity … so lets give it a spin here :

[TestMethod()]public void SalesOrderLogicTest(){   string connection = "metadata=res://*/OrdersModel.csdl|res://*/OrdersModel.ssdl|res://*/OrdersModel.msl;provider=System.Data.SqlClient;"       + "provider connection string='Data Source=.\\SQLExpress;Initial Catalog=EFLogicDemo;Integrated Security=True;MultipleActiveResultSets=True'";    using (EFLogicDemoEntities db = new EFLogicDemoEntities(connection))   {       SalesOrder order = new SalesOrder();       order.CustomerName = "Me";       order.OrderDatetime = DateTime.Now;       order.Discount = 2;       db.AddToSalesOrders(order);

       OrderItem item1 = new OrderItem();       item1.ProductName = "an Apple";       item1.Quantity = 5;       item1.UnitPrice = 2;       order.OrderItems.Add(item1);

       Assert.IsTrue(order.TotalAmount == 8);

       OrderItem item2 = new OrderItem();       item2.ProductName = "an Orange";       item2.Quantity = 1;       item2.UnitPrice = 10;       order.OrderItems.Add(item2);

       Assert.IsTrue(order.TotalAmount == 18);

       db.DeleteObject(item1);       Assert.IsTrue(order.TotalAmount == 8);

       item2.Quantity = 3;       Assert.IsTrue(order.TotalAmount == 28);   }}

That test worked like a charm and now you can Add and Remove and change about anything in your Entity’s properties and relations and rest assured that your calculation and logic will always be working behind the scene.

And please as you enjoyed the article and got some free code and knowledge, vote for the article and share your opinion and suggestions to keep me running and thinking of adding more articles.

kick it on DotNetKicks.com

About these ads

Tagged:

One thought on “Business Logic with Entity Framework

  1. 2010 in review « Maximum C# January 2, 2011 at 1:23 PM Reply

    [...] The busiest day of the year was April 8th with 26 views. The most popular post that day was Business Logic with Entity Framework. [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: