How do you guys manage your Adapter's

Posts   
 
    
Posts: 497
Joined: 08-Apr-2004
# Posted on: 25-May-2007 13:01:21   

Hi there,

This possibly belongs in the "Architecture" bit, feel free to move it...

I was wondering how people generally managed their adapter objects in their Business/Service level code. An example of what I mean:

CustomerServiceClass contains a method for listing customers - ListCustomers. This method needs to call a method on another class - ProductsServiceClass.ListProducts to get a list of products also. This method might even call other methods to get more info from the database...

Now, each of these methods needs to get code from the database, so you need to use an adapter class (assuming you're not self-servicing).. I wondered how people are managing this since each adapter creates a connection. At the moment we have a lot of code that just looks like this:

public DataTable ListBlah()
{
    adaptor = DataAccessAdaptorFactory.GetDataAccessAdaptor();
    // Do some LLBLGen magic
    adaptor.CloseConnection()
}

But this means that each method maintains its own adapter, so you have lots of connections being made. A singleton class or similar pattern-based approach might be better, what do you all think?

Rogelio
User
Posts: 221
Joined: 29-Mar-2005
# Posted on: 25-May-2007 14:14:24   

The singleton class or similar is not the correct approach beacause the adapter class is not stateless. For a single user application it may works; but what happens when you want to share the bussiness object amongs users (using remoting, web service, etc)?

I do the following: 1. Create a DataAccessBase class that contains the basic methods: UpdateEntity(entity as entityBase, refetch as bool, adapter as dataAccessAdapterBase) FetchEntity(.....,adapter as dataAccessAdapter) FetchCollection(......, adapter as...) FetchTypedList(......., adapter as ...) .........

Inside each method you check if the passed adapter is nothing, if it is nothing you create an adapter object, use it and dispose it at the end of the method. If it if not nothing you simply use it and let the calling object to take care of disposing the adapter.

  1. Create DataAccess class that inherits from DataAccessBase for each master entity (orderEntity is a master entity, orderDetailsEntity is not a master entity).

  2. The business classes (CustomerService for example) use the DataAccess classes. If the business class need to handles its process inside a transaction, then the business class creates the adapter, start the transaction and pass the adapter object to the dataAccess classes. If the business class does not need a transaction because maybe it only has to return a typedlist then call the dataAccess's method without an adapter.

Posts: 497
Joined: 08-Apr-2004
# Posted on: 25-May-2007 14:22:46   

Thanks!

Thats similar to some of the newer classes i've added. I created a "lazy loading" property called Adapter, which the methods use to get an adaptor. The first time that a method is called on the class, the property realises that the adapter doesn't exist, and creates one, storing it in a local private field value. The second time its called, it can simply return this one.

The downside to this is knowing when to close the connection - if you're not careful you'll leave the adapter open and waiting for GC to come and pick it up.

Another thing I did recently - I implemented IDisposable - that way I can added some code to the dispose method that closes the connection if its open. This is quite cool, but you do need to call the Dispose method on the class to make sure that you tidy up after yourself.

jmeckley
User
Posts: 403
Joined: 05-Jul-2006
# Posted on: 25-May-2007 15:56:19   

there is a shortcut to disposing (the object must implement IDisposable). I'll use DataAccessAdapter as an example.

using(IDataAccessAdatper adapter = new DataAccessAdatper())
{
    //perform work
}

once the code leaves the using segment _Dispose() _is called to clean up. also any objects declared within the using statement are out of scope.

If I have a service object that contains a _DataAccessAdapter _i will inherit the _IDisposable _and dispose of my adapter like this

Public Class MyService: IDisposable
{
   //MyClass Members
   private IDataAccessAdapter adapter;

   #region IDisposable Members
   public void Dispose()
   {
        this.adapter.Dispose();
   }
   #endregion
}

then I can instanciate MyService like this

using(MyService service = new MyService ())
{
    //call service methods
}

this ensures my adapter is closed and disposed when i'm finished with my service.

jmeckley
User
Posts: 403
Joined: 05-Jul-2006
# Posted on: 25-May-2007 17:15:21   

along the lines of DataAccessAdapters and BLL Services. I want to get your input on this model. I would have a base service class which contains an internal IDataAccessAdatper. the contstructor of the service could accept a BaseService as an argument and assign adapter value. example

//base class inherited by all data services
public abstract BaseService: IDisposable
{
     internal IDataAccessAdatper adatper;

     protected BaseService(IDataAccessAdapter adapter)
       {
             if(adapter == null)
             {
                  throw new ArgumentNullException("adapter cannot be null.");
             }

             this.adapter = adapter;
       }

     public void Dispose()
    {
        if(this.adapter != null)
        {
             this.adapter.Dispose();
        }
    }
}

//super class 1
public class MyService1 : BaseService
{
       public MyService1() : base(new DataAccessAdatper()) { }

       public MyService1(BaseService service) : base(service.adapter) { }

}

//super class 2
public class MyService2 : BaseService
{
       public MyService2() : base(new DataAccessAdatper()) { }

       public MyService2(BaseService service) : base(service.adapter) { }
}

I could then use the services like this

//with GUI button click event
protected void Click(object sender, EventArgs e)
{
   Service1 service1 = new Service1();
   Service2 service2 = new Service2(service1);
}

//within the Service2 class
public class MyService2 : BaseService
{
       //Ctors...

       public MyEntity FetchEntity()
       {
              Service1 service = new Service1(this);
              ...
       }
}

do you see any problems with this methodology? Things I havn't considered: * Accessing mulitple databases within the service. * How do I know when to close the connection or commit a transaction. (have boolean arguements?)(create public members in the BaseService class to all the GUI to access specific Adatper members via the Service.)

//base class inherited by all data services
public abstract BaseService: IDisposable
{
     internal IDataAccessAdatper adatper;
     ...
     public bool KeepConnectionOpen
     {
          get { return this.adapter.KeepConnectionOpen; }
          set { this.adapter.KeepConnectionOpen = value; }
     }

     public void CloseConnection(bool commit)
     {
          if(this.adapter.IsTransactionInProgress && commit)
          {
                 this.adapter.Commit();
          }
          this.adapter.CloseConnection();
     }
}
  • if I went this route I would need to be very careful of the _using _shortcut within my services so I don't dispose of my adapter before I'm finished using it, correct? I instanciate the adapter in the Ctor so I can actively know if/when it's not set. This could be an increase in system resources, but it seems better than instanciating the adatper on an as needed basis, plus i couldn't control which DAA to use if there are multiple dbs.
//I consider this risky
private IDataAccessAdatper adatper;
public IDataAccessAdatper Adapter
{
   get 
   { 
      if(this.adapter == null)
      {
         this.adapter = new DataAccessAdatper();
      }
      return this.adapter;
   }
   set { this.adapter = value; }
}