CSLA 3.6 Data Access Layer design

CSLA 3.6 Data Access Layer design

Old forum URL: forums.lhotka.net/forums/t/6390.aspx


Rajarshi posted on Tuesday, February 10, 2009

Hi,

I am rather new to .NET solution architecting and found Rocky's CSLA as a wonderful way to get to the bottom of things. Though I have gone through most important concepts presented in his C# 2008 Business Objects, I am more interested in implementing the framework and get up and running quickly. I am stuck at a position where he explains the Data Access Layer and mentions about "DataPortal_XYZ Methods Invoke Separate Data Access". There it has been explained how to create a separate data access object that may reside in a different assembly and that encapsulates the data access in the DataPortal_XYZ methods. While the DataPortal_Fetch routine is neatly explained with a DataReader example a DataPortal_Insert example is not provided and I am unable to figure the most appropriate way to implement the DataPortal_Insert code in this model (separate data access object in separate assembly).

I cannot pass the business object directly to the Data Access layer as that would require a reference to the Business Object Layer from DA Layer causing a circular reference error in the VS 2008 IDE. Transferring the DA class to the same assembly of BO might solve this but then again loose scalability and I am not too sure whether that would be a suitable approach when Autogenerated Id values need to be returned to the BO (I guess the IdProperty on the Business Object would be ReadOnly and hence cannot be assigned the new value generated by the database while transferring back from DA to BO).

So in this situation what should be the best approach -

1. Implement a 'SaveObjectXX' method in the Data Access layer that simply accepts .NET type method parameters and that will be called from the DataPortal_Insert. E.g. SaveRole(String name, int PolicyId).

2. Implement Data Transfer Objects to pack the data from Business Objects and send the Data Transfer objects to the DA layer for saving. Won't it be too tiring to generate DTOs for a decent sized application and less performing (due to loading/unloading from the DTOs).

3. Any other suggestions.

By the way, I prefer to stick to ADO.NET rather than LINQ for my current assignment so the examples in the latest book does not quite satisfy my needs. Actually I don't have enough time to open another front on learning LINQ.

Sorry for being lengthy, but wanted to clarify things as much as possible. Need help eagerly.

RockfordLhotka replied on Tuesday, February 10, 2009

Your summary is correct. The two primary options are for the DAL to expose a set of strongly typed methods like InsertCustomer(x,y,z,a,b,c), or to use a DTO.

The DTO approach does require more code, and has more overhead, but provides really good decoupling. So in some ways it provides the better answer, in that it is more flexible and probably more maintainable.

But the strongly typed DAL method approach is simple, requires a lot less code, and can also be reasonably decoupled if you use interfaces to define the DAL (so you can more easily swap one DAL implementation for another, because the business object is just using the interface).

Rajarshi replied on Wednesday, February 11, 2009

Thanks your Rocky for your prompt reply. If you ever had the time to read Indian mythology 'Mahabharata' you will find two characters 'Dronacharya' and 'Eklavya', the later being the student of Dronacharya, a legendary archer. The interesting part being that Eklavya had never seen Drona or met him, he just placed him as his Guru in mind and soul and practised all by himself and became a master archer himself. What happened next is a long story but I have started considering you as my .NET Architecture Guru even though I might not get a chance to meet or talk to you ever. Thanks for all your efforts on CSLA and being so helpful on the forum. I have started developing a real life application based on CSLA.

Coming back to the discussion, I got your explanation clear but a little confusion remains. You are suggesting to use Interfaces to decouple BO layer (uses the Interfaces) and DA layer (defines and implements the Interfaces) so that DA implementation can be changed anytime. Now, consider without using Interfaces, I have a method like InsertCustomer(a, b, c, d) which is called by the BO from DataPortal_Insert(). Both BO and DA layers are implemented in separate assemblies. At a later time, if I want to change the implementation can't I just rewrite the code in InsertCustomer method in DA and replace the new DA assembly in the application server. Will that not be considered as decoupling or will it pose some issues in any ways. Is this approach practical?

When I tried to further analyse what you could have indicated, I found that the BO needs a reference to the DA in the above approach and hence the DA assembly always has to be of the same name and use same methods even if I change the implementation in InsertCustomer from ADO to say LINQ. Hence, I tried to eliminate the reference altogether by introducing a third assembly with only required Interfaces that is referenced by both BO and DA. Hoping that this would enable me to change the DA assembly anytime with another DA assembly with a different assembly name, interface implementation etc. which could reap some maintenance benefits. But I think that was an impossible thought as I found that I need an object of a class that implements the Interface and the InsertCustomer will have to be called (on that object of the class). This forces me to keep the reference to existing DA assembly (from the BO assembly) and use the DA objects in BO, though through Interfaces like in ICustomer c = new CustomerDAL (CustomerDAL implements ICustomer) If this is right then is there any difference from the above approach (rewriting InsertCustomer in same DA assembly) with an Interface based approach to achieve decoupling?

Considering this, could you please give a little hint towards how interfaces can help decoupling in such cases.

My entire thought process may be wrong but I could not find any suitable answer from any person or on the net and hence had to resort to your help.

RockfordLhotka replied on Wednesday, February 11, 2009

Rajarshi:

Thanks your Rocky for your prompt reply. If you ever had the time to read Indian mythology 'Mahabharata' you will find two characters 'Dronacharya' and 'Eklavya', the later being the student of Dronacharya, a legendary archer. The interesting part being that Eklavya had never seen Drona or met him, he just placed him as his Guru in mind and soul and practised all by himself and became a master archer himself. What happened next is a long story but I have started considering you as my .NET Architecture Guru even though I might not get a chance to meet or talk to you ever. Thanks for all your efforts on CSLA and being so helpful on the forum. I have started developing a real life application based on CSLA.

Thank you! Both for your kind words, and for sharing a bit of mythology. I love mythology, but have never looked into Indian mythology (mostly Greek, Egyptian and Sumerian). I've got to believe that Indian mythology is incredibly rich and interesting.

To your question, the reason you need interfaces to decouple the DAL is exactly what you say - without interfaces the BO assembly must directly reference the DAL assembly, which means you can't have more than one DAL.

You may want more than one DAL assembly for many reasons. One is to support more than one database (SQL Server and Oracle for example). Another is for testing, where you want a "mock" DAL that simulates talking to the database for testing, and a real DAL that talks to the database for actual use.

The idea isn't too hard. Create three (or more) assemblies:

  1. BO assembly
  2. DAL interface assembly
  3. DAL assembly (one or more)

The BO and DAL assemblies will reference the DAL interface assembly. The DAL objects will implement the interfaces.

The tricky bit is that the BO needs to use dynamic type loading to load the actual DAL assembly. Normally this is done by a class in the DAL interface assembly, so the BO code can use it.

Your DataPortal_XYZ method looks like this then:

protected override void DataPortal_Insert()
{
  var dal = DalInterface.DalFactory.GetCustomerDal();
  using (BypassPropertyChecks)
    dal.Insert(Id, Name, City, ...);
}

The DalFactory class just has a bunch of static methods to get the DAL objects for each type of data. There are many ways to build these methods, but usually they drive off a config file setting to get the assembly name of the actual DAL assembly you want to use.

public static ICustomerDal GetCustomerDal()
{
  string assemblyName = GetNameFromConfig();
  Type dalType = Type.GetType("Dal.CustomerDal," + assemblyName);
  return Activator.CreateInstance(dalType);
}

Keep in mind I'm typing this off the top of my head, so this may not be perfect, but hopefully you get the idea.

Finally, every DAL assembly must implement the DAL classes, which implement the interfaces:

namespace Dal
{
  public class CustomerDal : DalInterfaces.ICustomerDal
  {
    public void Insert(...)
    {
      // do insert here
    }
  }
}

There are other techniques too, but this is a pretty good one overall.

Rajarshi replied on Wednesday, February 11, 2009

Thanks once again. That was of great help. Will try it out tomorrow. It gives me enough confidence to see that I was at least 'thinking' in the appropriate direction. With a little help from you, I am sure I will be able to build my dream apps on CSLA. I will also try to preach CSLA within the developer community in Kolkata, India if I can taste success with it.

Copyright (c) Marimer LLC