Using Telerik OpenAccess ORM in N-Tier applications

by OpenAccess ORM Team | Comments 16

Hello, by means of introduction, my name is Alexander Filipov and I am working as a developer for the Telerik OpenAccess team. In my first post I would like to share some thoughts about using Telerik OpenAccess ORM in advanced n-tier web applications. Undoubtedly, the main goal in such architectures is to lose-couple the tiers from each other, so the code is modular and easier to maintain. Here comes the question how Telerik OpenAccess ORM fits into this scenario and which are the layers that it should be used in.
The optimal approach is to have not more than two layers that “know” about OpenAccess. One of them is the Data model containing Persistent classes. The other layer is the Business logic that operates on the persistent model and provides data to the upper tiers. This data can be wrapped in additional middle-tier business objects to isolate the OpenAccess specific persistent objects from the rest of the application. These business objects should not depend on the DAL and can be used as transport objects all the way through to the Presentation layer.  It is a good practice to use an interface to define the functionality required from the Business logic. This will make relatively easy to replace the BLL and DAL with another data provider (implementing the interface) without changing the upper layers.
During the last few weeks we published two demo applications with similar design.  I will focus on the simpler one to demonstrate the architecture in action. The workflow is illustrated on the diagram below.

  • The presentation layer requests objects from the business logic layer of the data provider;
  • The business logic layer executes the relevant query;
  • The data access layer retrieves persistent objects from the Database and returns them to the BLL;
  • The business logic layer uses a set of Assembler classes to wrap the persistent object data into business objects and sends them to the next layer.

 Layers

Write operations work the same way except that the presentation layer passes an object to be stored.
The other demo project uses a WCF service to distribute data to the Presentation layer. It also has a mechanism for loading dynamically the data provider assemblies. This provides the ability to have many data providers and specify in a configuration file which of them to use. This project is available for download in our Code library as well.

16 Comments

ScottyG
Has anyone looked into using OpenAccess ORM with the CLSA.NET Framework?
Daniel Plomp
Hi Alexander, thanks for your post! Would you be willing to examine a project of my, that I'm building with OpenAccess? Just to make sure that I'm on the right way?
Henrik
Hi Alexander,

Exactly architected as our solution which is also based on WCF

Except, instead of providers we use depency injection to inject the correct implementation of the business logic interface based on who the "tenant" is. We have a multi-tenant solution where different tenants can use different implemenations of the business logic interface.

Thanks for sharing though - it seems like we are doing things ok then.
Alexander Filipov
Hi Daniel,
Just send us the application attached to a support ticket and I will evaluate if something can be optimized.

Regards,
Alexander
Richard Brown
Hi Alexander,

I just wanted to say a big thank you. I've read just about every architecture related article on Telerik's website several times, and to my mind the one that most closely fits my needs and knowledge is your simpler Northwind application.

I'm just now reworking our code base to fit with this structure.  It all is making sense until I get to the issue of linking for object to object at the BO level. Do you have any "rules of thumb" or guidelines as to how to handle passing around business objects that might or might not regularly need access to child objects etc?

Many thanks!

Richard.
Richard Brown
Hi Alexander,

Do you have any plans to extend the simpler demo application?

Possibly implementing a web service, and fleshing out the flow of ojects a bit more, with the ability to add object and apply business logic rules to them?  I think this would fully answer a lot of the remaining questions I have.

For myself I am trying to understand how to migrate from the simple application to a full WCF service type one in the near future as our needs expand.

Thanks!

Richard.
Nicolo
Hi Alexander

Would you propose this architecture for a windows application (windows user interface instead of a web ui)?

Thanks!

Nicolo
Alexander
Hi Nicolo,

Sure, if you want to have stronger separation of concerns you can use this approach in desktop applications as well. This way you will be even able to easily switch the UI layer at a later point, if necessary. Just have in mind that this would take a bit more time to implement.

Regards,
Alexander
Hugo Augusto
Hi, Alexander

You should remove the link to the simpler project because it's not respecting in any way the louse coupling between tiers. You have a reference to OpenAccess in the Dataprovider Interface. In the WCF demo that does not happen. The other example will only confuse people.

Also I already wrote somewhere that I don't see any advantages using OpenAccess the way you did. We have this wonderfull ORM that automatically maps a database into BOs. The problem starts right here. OpenAccess is not mapping the database directly to our own BO's.

This will force us to write those assembler classe you wrote for "translating" OpenAccess Bussiness Objects generated automatically, into our own BOs for the sake of low coupling.

Don't you feel that writing all those assemblers classes is somehow to do what OA already has done? We are duplicating objects! On a small project that is ok, but if we are working with a lot of entities, this is a painfull job.

Why can't I just map the database into my own BOs like in NHibernate, or have an automatic class provided by Telerik that does that translation for me based on some kind of configuration.

In the OADataProvider Implementation, in a Get method I would call something like:

public Customer GetCustomer(int customerID)
{
    using (DAL.NorthwindEntityDiagrams ctx = new DAL.NorthwindEntityDiagrams())
    {
        IQueryable<DAL.Customer> query = ctx.Customers.Where(p=>p.CustomerID == customerID);
        Customer result = ctx.AssembleFrom(query, Customer);                            
    }
}

Of course there should exist also a generic AssembleTo utility method available. These mapping methods would work according to the Existing Domain Model and any rules specified in an xml or the Domain Model project itself. What do you think about this? Am I crazy? :)
Alexander
Hello Hugo,

I am not sure which OpenAccess reference you are referring to but the only projects that depend on OpenAccess in this demo are the Telerik.NWA.OADAL (containing the domain model) and the Telerik.NWA.BLL which translates the persistent objects to business objects and vice versa. This is indeed the correct setup.

You are correct, writing those classes manually could be a quite painful effort but we are aware of that and we are going to provide a way to automate the process, most probably in Q3. We will have your suggestions in mind when we start working on that.

Best regards,
Alexander
Hugo Augusto
Hi Alexander,

The example I'm refering to is the one in the sentence "  I will focus on the simpler one to demonstrate...". That example is not a very good example and should not be used as a reference. The WCF demo project is the right way to go when using OA in disconnected mode.

Concerning the other matter, I'm glad you are trying to work something out to spare developers from the endless work of writing mappers. The only  way that makes sence using a disconnected approach with OA ORM, is to have as you said, some kind of mapping process automation or DTOs. Yes, it's wonderfull not to have to write SQL queries but it's not worth if we have to write mappers. I hope Telerik works on something easy to implement and frees us once and for all! Can't wait for that Q3 release :)
Nicolo
Hi Alexander
I refer to the simpler n-tier application you mention here. I'm trying to build a Telerik WinForms UI with RadGridView on top of  that architecture. My question: how can i achieve the behaviour of the RadGridOrders_UpateCommand procedure for a WinForm RadGridView (look at the UpdateValues Method at Line 7)?
1     Protected Sub RadGridOrders_UpdateCommand(ByVal source As ObjectByVal e As GridCommandEventArgs) 
2         If e.Item.OwnerTableView.ParentItem Is Nothing Then 
3             Dim orderID As Integer = CInt(Fix((CType(e.Item, GridEditFormItem)).GetDataKeyValue("OrderID"))) 
4  
5             Dim editedOrder As New Order() With {.OrderID = orderID} 
6             CType(e.Item, GridEditableItem).UpdateValues(editedOrder) 
7             dataProvider.UpdateOrder(editedOrder) 
8         Else 
9             Dim dict As IDictionary = New Hashtable() 
10             Dim item As GridEditFormItem = CType(e.Item, GridEditFormItem) 
11             item.OwnerTableView.ExtractValuesFromItem(dict, item) 
12  
13             Dim orderID As Integer = Integer.Parse(dict("OrderID").ToString()) 
14             Dim productID As Integer = Integer.Parse(dict("ProductID").ToString()) 
15  
16             Dim editedOrderDetail As New OrderDetail() With {.OrderID = orderID, .ProductID = productID} 
17             CType(e.Item, GridEditableItem).UpdateValues(editedOrderDetail) 
18             dataProvider.UpdateOrderDetail(editedOrderDetail) 
19         End If 
20     End Sub 

Kind regards
Nicolo
Nicolo
update: look at the UpdateValues Method at Line 6
Alexander
Hello,

@Hugo: We will update the example so that it uses a ProviderFactory class and remove the reference to the Telerik.NWA.BLL in the web site. I guess it would be closer to the WCF demo this way.

@Nicolo: There is no such method like UpdateValues in the WinForms RadGridView API but actually you do not need it. You can just hook to the CellEndEdit event and do the following:
C#
private void radGridViewOrders_CellEndEdit(object sender, Telerik.WinControls.UI.GridViewCellEventArgs e) 
     dataProvider.UpdateOrder(e.Row.DataBoundItem as Order); 
VB
Private Sub RadGridViewOrders_CellEndEdit(ByVal sender As System.Object, ByVal e As Telerik.WinControls.UI.GridViewCellEventArgs) Handles RadGridViewOrders.CellEndEdit
   dataProvider.UpdateOrder(TryCast(e.Row.DataBoundItem, Order))
End Sub

I am afraid that currently it is not possible to have a hierarchy view in the RadGridView as it is shown in the ASP.NET demo. This functionality is being implemented at the moment and should be available in one of the upcoming service packs.

Regards,
Alexander
Nicolo
Thank you
Now the next question. How can I send a new user added row (by the UI, on top of the Grid) to the model? In this case the e.Row.DataBoundItem is empty. What Gird-Event sends the values and which property returns the cell values? Sorry for asking again, but i can't find a sample for this.

Regards,
Nicolo
Hugo Augusto
Hi Alexander,

that would be great. Do you think you can warn me when the example gets updated? I would like to peak at it. Thank you.

Comments

  1.    
      
      
       
  2. (optional, emails won't be shown on public pages)
  3. (optional)
Read more articles by OpenAccess ORM Team - or - read latest articles in Developer Tools