RecentComments

Comment RSS

Domain Driven Design, Business Objects, Datasets, NHibernate and friend Jack (Part 2/2)

by Ioannis 12. February 2009 19:59

 

In the previous post, we have discussed some issues that emerged from a conversation with my friend Jack. In this post we will explore a little bit his following statement:

Jack: Well(…) I have created a BO (a simple one, mapped to a single table in the DB) and created a very simple DataLayer using NHibernate to retrieve a list of 1500 BOs and display them in a DataGrid. It took NHibernate 6 sec to retrieve the data! Can you believe it? (…) I have tried the same thing with a DataSet and it took only some msec (…)  I tried to find a solution to this in the internet for 3 hours and found nothing. NHibernate is poorly documented too… Nothing beats DataSets.

This needs proof. This needs code. So I have implemented a small application as my testbench to perform my measurement with NHibernate. The TestBench is as follows:

We create a small DB in MS SQL with a single table and 20000 records:

As you can see the table consists of a Primary Key (ID – Bigint) and 5 columns with strings (String1..5) of type nvarchar(50).

Now we go to Visual Studio, create a new application and implement the Business Object as follows (this is what Jack did):

 

That is we provide a Property and a Field for every column in the Table. The FirePropertyChangedNotification(value) method is at the parent GenericBO class and is implemented as follows:

Which is the typical BO’s support of the INotifyPropertyChanged interface needed for updating the GUI correctly in data binding scenarios.

The next thing was to set up NHibernate and provide the mapping file between the table and the BO:

Now it was time to perform some tests. I decided to test several ways of retrieving the list of TestClass BOs both with NHibernate Session and SessionStateless. So the tests are as follows (all tests return List<TestClass> unless explicitly specified):

 

I got the following times (for test 3 to work I needed to specify a property ID named as the column in the Table in TestClass whose accessors are accessing the field _primaryKey) :

  Test 1 Test 2 Test 3 Test 4
1st Time 26,078sec 23,927 sec 23,113 sec 23,735 sec
2nd Time 0,117 sec 0,098 sec 23,050 sec 0,106 sec
Times include time to display in WPF DataGrid

The results are disappointing. Of course the second time, since there is no change in the Cache the times are very low (in Test3 the times are the same for the first and second time since we are performing a plain mapping with a transformer) but what happens in the first Time? Will we have better lack if we perform the same tests in a StateLess session?

  Test 1 Test 2 Test 3 Test 4
1st Time 25,573sec 24,890sec 24,531sec N/A
2nd Time 25.041 sec 25,029 sec 23,427sec N/A
Times include time to display in WPF DataGrid

Now we are worse off. First and Second time are huge due to the absence of the cache. Was Jack right after all? Before jumping into conclusions let’s enable logging for NHibernate and see the log:

Retrieval starts at:

2009-02-11 21:41:05,268 [10] DEBUG NHibernate.Loader.Loader - processing result set
2009-02-11 21:41:05,268 [10] DEBUG NHibernate.Loader.Loader - result set row: 0
2009-02-11 21:41:05,274 [10] DEBUG NHibernate.Loader.Loader - result row: EntityKey[ORMTests.TestClass#1]
2009-02-11 21:41:05,279 [10] DEBUG NHibernate.Loader.Loader - Initializing object from DataReader: [ORMTests.TestClass#1]
2009-02-11 21:41:05,285 [10] DEBUG NHibernate.Persister.Entity.AbstractEntityPersister - Hydrating entity: [ORMTests.TestClass#1]
 

First phase ends at:

2009-02-11 21:41:11,949 [10] DEBUG NHibernate.Loader.Loader - result set row: 19999
2009-02-11 21:41:11,949 [10] DEBUG NHibernate.Loader.Loader - result row: EntityKey[ORMTests.TestClass#20000]
2009-02-11 21:41:11,949 [10] DEBUG NHibernate.Loader.Loader - Initializing object from DataReader: [ORMTests.TestClass#20000]
2009-02-11 21:41:11,949 [10] DEBUG NHibernate.Persister.Entity.AbstractEntityPersister - Hydrating entity: [ORMTests.TestClass#20000]
2009-02-11 21:41:11,949 [10] DEBUG NHibernate.Loader.Loader - done processing result set (20000 rows)

First phase takes 6 seconds !

Second phase starts at:

2009-02-11 21:41:11,957 [10] DEBUG NHibernate.Engine.TwoPhaseLoad - resolving associations for [ORMTests.TestClass#1]
2009-02-11 21:41:11,962 [10] DEBUG NHibernate.Engine.TwoPhaseLoad - done materializing entity [ORMTests.TestClass#1]

Second phase ends at:

2009-02-11 21:41:32,601 [10] DEBUG NHibernate.Engine.TwoPhaseLoad - resolving associations for [ORMTests.TestClass#20000]
2009-02-11 21:41:32,602 [10] DEBUG NHibernate.Engine.TwoPhaseLoad - done materializing entity [ORMTests.TestClass#20000]

Second phase takes 21 seconds !

With a little research it seems that in the second phase NHibernate performs the mapping of the raw values to the Business Objects. To verify that we run Test 3 again but this time we do not map the results to BOs: 

 

Now the time has decreased to : 1 sec !

There must be a delay when mapping the data to the BOs. So I have manually added the code to map the data to the TestClass Business Objects just after getting the List<object> ListReturned as follows: 

 

The retrieval time returned to 15,227sec which is an improvement from 23sec but still not acceptable.

So the problem is not with NHibernate but rather it is in the way we have implemented the BO. And the first suspicious place where this may be happening is when calling the FirePropertyChangedNotification(…). So we first remove from the function the automatic retrieval of the Property’s name which may cause the delay:

(StateLess Session)

  Test 1 Test 2 Test 3 Test 4
1st Time 8,855sec 8,827sec 4,651sec N/A
2nd Time 8,638sec 8,815sec 4,170sec N/A
Times include time to display in WPF DataGrid

We have 50% increase in performance. How about removing the method call completely and putting its behavior directly in the properties?

(StateLess Session)

  Test 1 Test 2 Test 3 Test 4
1st Time 0,813sec 0,510sec 0,331sec N/A
2nd Time 0,490sec 0,553sec 0,320sec N/A
Times include time to display in WPF DataGrid

Which is now acceptable. To make sure we try to load the same data using a DataSet which gives approximately 0,301sec.

The last thing to do is perform the comparison between Test2 and DataSets for increasing table size:

   

Apparently there is a difference in DataSets but now this difference is justified since NHibernate is an ORM tool which is more than a simple mapping tool which creates the DataSets.

As a conclusion, Jack was again wrong. Wrong, because it was his implementation that lead to this big stall in performance and not NHibernate itself. Moreover, when he was searching the internet for a solution it was normal not to be able to find one since the issue was caused by his way of implementing things.

My effort is not to advertise NHibernate. I am sure that the same would emerge with EDM or any other ORM tool. The point of this 2 post discussion is three-fold:

  • First to show a way of thinking which in my opinion can lead to overstatements.
  • Second to provide a general overview of DDD, ORM, DataSets and Business Objects.
  • Third to show some performance analysis results when using NHibernate and a way to resolve issues about those.

 

kick it on DotNetKicks.com

Tags:

.NET | Databases

Domain Driven Design, Business Objects, Datasets, NHibernate and friend Jack (Part 1/2)

by Ioannis 12. February 2009 19:40

 

A few days ago, I was having some drinks with a friend (let’s call him Jack) in a bar discussing about enterprise application development and the migration from DataSets with VS to Business Objects with NHibernate. I will try to reproduce the conversation here:

Jack:  Oh man NHibernate really sucks! It is very slow compared to DataSets. The things about Business Objects you were saying are all theoretical mambo-jumbo. Datasets rock.

Me: Why do you say that? What did you do?

Jack: Well, I found some time in the weekend and have followed the DDD paradigm instead of using DataSets. I have created a BO (a simple one, mapped to a single table in the DB) and created a very simple DataLayer using NHibernate to retrieve a list of 1500 BOs and display them in a DataGrid. It took NHibernate 6 sec to retrieve the data! Can you believe it? (…) I have tried the same thing with a DataSet and it took only some msec (…)  I tried to find a solution to this in the internet for 3 hours and found nothing. NHibernate is poorly documented too… Nothing beats DataSets.

There are a lot of things to discuss in Jack’s statement.

First of all, it took just a 1 hour of playing with NHibernate for Jack to claim that the NHibernate technology sucks due to inexplicable performance issues in such a small example. It took him another 3 hours to claim that the documentation for NHibernate is insufficient. And this whole experience was enough for him to judge... But since this issue has nothing to do with programming, we will leave it to the philosophy blog.

Another issue worth discussing here is the fact that Jack is comparing NHibernate with DataSets and relates the first with Business Objects and then says that he followed the DDD programming paradigm. A lot of terms whose connection is not clear in his mind. How do they relate? This is about philosophy again. But this time it is about philosophy of designing programs and I will discuss it here…

Enterprise applications share a general set of requirements. There are some data that need to be deleted, inserted, updated, selected and filtered in various ways. Those data are stored (persisted) in a database. There are several rules (depending on the application) that define how those data are entered, processed, validated and sometimes automatically generated. Finally there is the graphical user interface that provides the means of playing with those data.

The keyword here is “The  Data”. Every “logic” in the application (Business, GUI, Data access) needs “The Data”. “The Data” are retrieved from the database, processed through classes in the business logic and presented through events in the GUI. So how are “The Data” organized? And how are “The Data” persisted? It turns out that this has a lot to do with how we design the application in our minds in the first place. Let us call “The Data” as a set of carefully designed classes also known as “Business Objects”.

The common ground for everyone and for a long time was the database. The relational database with the rules it implied (Tables, Views, Primary and Foreign Keys) provided a starting point on organizing “The Data” and as a consequence our BOs.

To make this point more clear imagine the following simple scenario where we need to implement an application involving Clients, Products and Purchases where a client buys a number of products which are written on an Invoice with a unique Invoice Number. Note that a lot of us, even before hearing anything about the application’s requirements, we have created a conceptual Database diagram in our mind that looks like the one below: 

So “The Data” are conceptually organized in three tables and associations between them. All my application will be using select like statements operating on relations on table rows. Therefore my Business Objects will be mainly sets of DataTable, DataRow and Relation classes mimicking the database. In other words they will be DataSets. Yes DataSets are Business Objects since they are a way to organize “The Data” of the business.

But is this formulation of data convenient for my application (or Domain)? Note that up to now we have not said anything about the application’s requirements.

What if the main requirement for the application (ie the Domain) is to show the current Invoices or operate on Invoices?

With the DataSet approach we would probably fill a Purchases DataTable with the DataRows that have a specific InvoiceNo and operate on it.

Wouldn’t it be more convenient if we had an “Invoice” as “The Data”? Do we need to change the Database?  The answer is no. The key point here is to decouple the application’s organization of “The Data” from the limitations the relational database imposes. We want to use Invoices in our business logic therefore we will create an “Invoice” Business Object:


 

There is no doubt that organizing our data like that has a lot of benefits. Actually, we have roughly followed the Domain Driven Design paradigm where we have implemented our Business Objects according to entities of the actual domain and the application’s requirements. There was nothing evil with our Datasets and the tabular like business objects. They just weren’t suited for the requirements of the particular application (the domain). In another application or as part of a domain datasets may be the most suitable choice (try accounting journal entries and you will see what I mean).

No matter what our BOs are (Datasets or other) there is always the need of mapping them to the Relational Database. Note here that the mapping is not a simple one to one connection of table fields to BO properties. Most of the time it requires more than that. For example creating a new Invoice BO in the previous example and adding a Client and a Product into it is persisted by adding a new record in the Purchases table with the appropriate Client and Product keys.

Here comes the role of ORM tools such as NHibernate. Of course along with the previous functionality those tools offer a lot more such as session management, concurrency control etc. So ORM tool provide methods for implementing the Data Access layer ASAP. So why do people pose the question Datasets vs Business Objects? Or why did Jack said that he prefers DataSets over NHibernate? That is because Visual Studio provides an automated way of creating the DataSets for you if you have the database ready. It is as if Visual Studio is creating your ORM tool that will handle your DataSets to DB communication. And it happens in a few seconds.

ORM tools such as NHibernate favor starting building your application from your Business Objects that fit your domain. Then they let you define how your BOs will be persisted (define the DB Schema) and request from you to provide a mapping between the two. They can then give you the goodies for manipulating the data. So for someone who already has the Database ready, this seems like a big overkill. But it is not always such a big deal since ORM tools usually provide third party tools that can construct some BOs automatically from tables of the database.

So here is the basis of the actual debate:

The verdict?

  • If the application is small scale and you don’t have the time, use DataSets and go have fun (unless fun is discussing about programming).
  • If the application is not small scale then see if the DataSet tabular logic fits in your Domain and if it does use it.
  • For the rest be custom and use ORM tools (by the way EDM is Microsoft’s suggestion so if you are into Microsoft go for it).

So we have actually questioned Jack’s personality and have shown that he has used terms without really knowing what they meant. In the next post we will prove that Jack was also wrong about the performance issues.

“Sorry Jack”

kick it on DotNetKicks.com

Tags:

.NET | Databases

WPF XAML SYNTAX 101

by Ioannis 16. December 2008 08:21

DownLoad in .pdf (145,97 kb)

This post provides the basic key points in order to understand the WPF XAML syntax and what is going on behind the scenes in the XAML Processor. Although you may be the kind of guy/girl who prefers to learn through writing/reading code, I recommend reading this article since it may save you a lot of time when trying to figure out how to combine the XAML Elements together.

First things first, we need to define what the XAML processor does. Well, the XAML processor as the following figure suggests, receives XAML XML language constructs and translates them to code that will be compiled to run in the .NET Framework. 

So the user writes the XAML File and some source code.

Behind the scenes the XAML File is translated to code by the XAML Processor. The translated code is combined with the source code and the final merged product is compiled and leads to the desired WPF application.

The programmer that was used in programming for Windows Forms, apart from learning the new language constructs, he/she also needs to learn the XAML syntax and how it is translated to code. This is the main topic of this article. So we will be interested in this translation:

First of all, in any XML document we have XML elements and XML attributes. For the XAML processor Elements are Class Instantiations and XML Attribute-Value pairs are Class Property-Value assignments.

For example the following table shows equivalence for the instantiation of a class of type Button:

But as you know classes reside in namespaces. So how can you define a namespace to locate the classes that you need?

At the beginning of a XAML file there are two definitions:

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml

The first one is the actual declaration of the WPF namespace and since it is not followed by a “:” it is the default namespace. Since “Button” does not have a “:” prefix its definition will be expected to be in there.

On the contrary the next namespace defines the XAML syntax and will carry the “x” name throughout the document. Actually the x namespace carries some special directives to the XAML Processor and does not necessarily follow the typical Attributes to Properties mapping. For example the “x:Name” attribute in the Button declaration instructs the XAML Processor to create a named instance for the Button class because we want to be able to access it through code.

So if you want to use in your XAML File your own classes and controls you need to define your namespace in XAML. The following example code snippet defines two namespaces the one (Entities) that will be named tools and resides in Entities.dll and the other (Force) that resides in the same dll with the XAML file.

xmlns:tools="clr-namespace:Entities;assembly=Entities"
xmlns:local="clr-namespace:Force"

Moreover the definition:

x:Class="Force.MainClass"

states that there will be a code-behind class MainClass which will be used in conjunction with the XAML File which also carries code for the MainClass class.

But wait a second, in the previous example the property IsEnabled is Boolean and is assigned in XAML the value of “True” which is a String. And what will happen if the property is of type “Int”?

Well, when the programmer writes in XAML IsEnabled=”True” the XAML Processor does the following: It locates the property and finds out its type. It searches to find whether there exists a special class named “Type Converter” defined for the type. The type converter is a class that is fed by the XAML processor with the attribute value (eg “True”) and returns a mapping of that value to the actual type (eg the Boolean value True). So for the Boolean type there is a Type Converter class that transforms String literals to Boolean values. You can create your own type converters for your own types (classes) by following the instructions in the following nice articles:

How to: Implement a Type Converter
Walkthrough: Creating a Type Converter for the WPF Designer

Ok so we know how to instantiate classes in XAML and assign values to properties through the use of type converters.

Now we need to define how “Nesting” is interpreted by the XAML Processor. Nesting is the process of containing an XML tagged block within another. In XAML WPF the way nesting is handled is defined by the class that is instantiated.

For example nesting in the Button class is equivalent to assigning a value to the property “Content”.

Or in the ViewPort3D class nesting is equivalent to adding items to the property Children which is of a list type.

In general nesting either gives value to a specific “default” property or adds another element in a property that defines some kind of list.

A specific nesting type answers the previous question of giving values to properties that have to do with instantiating other classes. If a nested block is defined by properties of the class written in the dot syntax, then the contents are setting the value for this property:

To summarize up to now we can fully understand the following XAML files:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"> 
    <Button x:Name="button1" IsEnabled=”True”>Test</Button>
</Window>

A button class is defined with its Content property equal to Test. The class is named button1. The property IsEnabled is assigned the Boolean value true through the use of a type converter that converts string values to Boolean. The property Content of the Window top-level class has the value of the instantiated button.

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Button x:Name="button1" Content="Test" IsEnabled=”True”/>
</Window>

Same as before without using the nesting.

Another way of setting the value to a property is by using the nesting as a property setting mechanism. For example, to set the Content property of the previous example we could:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    Title="Window1" Height="300" Width="300">  
   <Button x:Name="button1" IsEnabled=”True”> 
       <Button.Content>Test</Button.Content> 
    <Button/>
</Window>

This way is especially useful when we want to instantiate whole new classes to be values for properties of objects. In the previous example the window class sets by default the content property through nesting which will be assigned a reference to the Button class. It is equivalent to:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 
   Title="Window1" Height="300" Width="300"> 
   <Window.Content> 
       <Button x:Name="button1"> 
            <Button.Content>Test</Button.Content> 
        </Button> 
    </Window.Content>
</Window>

But there is another way for setting values to properties through the use of Markup Extensions. Markup extensions are either defined by curly braces or as nested values for setting properties. For example:

<GridViewColumn Width="Auto" Header="Επωνυμία" 
                   DisplayMemberBinding
= "{Binding Path=Logo}"/>

Is equivalent to:

<GridViewColumn Width="Auto" Header="Επωνυμία">
           <GridViewColumn.DisplayMemberBinding> 
            <Binding Path="Logo"/> 
      </GridViewColumn.DisplayMemberBinding>

</GridViewColumn>

Markup extension classes tell the XAML Processor to create an instance of the defined class (in our case the Binding class), set some properties (in our case the Path property is set to “Logo”) of the class and run the constructor with some parameters (in our case no parameters are passed) and call the ProvideValue member of the extension class to get the value that will be assigned to the property. The general syntax is as follows:

{MarkupExtensionClass
        
ConstructorArg1, ConstructorArg2,…,ConstructorArgN,
         Property1=Value1,Property2=Value2,…,PropertyN=ValueN
}

There is already a whole bunch of predefined markup extensions. Their summary can be found in the following:

Markup Extensions in XAML

This summarizes a brief introduction to the WPF XAML syntax. Happy coding.

kick it on DotNetKicks.com

Tags:

.NET | WPF

Powered by BlogEngine.NET 1.5.0.7

Programming Blogs - BlogCatalog Blog Directory Add to Technorati Favorites

MVP Award

Ioannis Panagopoulos





This blog is using BlogEngine.Net and is hosted in the hoster below. I have not experienced any problems installing BlogEngine.Net in the host and I am satisfied with the host's response times. Therefore I recommend it.


DiscountASP Add