Best Practice Advice On Application Business Objects

Best Practice Advice On Application Business Objects

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


NickTaylor posted on Friday, July 24, 2009

Hi,

I wonder is someone can offer some best practice advice / guidance on the following please:-

I am in the process of converting an internal application from Visual FoxPro to DotNet using the CSLA framework. Given that our existing application is written Foxpro 2.6, tables are free and are not contained in a database. Typically I have one CSLA business object per individual table and I access / insert / update table data via OLEDB. The business objects work very well, and the factory methods provide simple entity retrieval methods such as ( in the case of BoCustomer ): GetCustomerByName(string Name), or GetCustomerByID(string ID). Again this works very well, and is very scalable.

However as my application is growing I have a increasing requirements for lots of “command” type objects. For example, I may wish to retrieve a datatable containing a list of all customers with open sales orders ( i.e. data from multiple tables ), or a list of customers with open sales invoices. Some of these may be simple SQL select commands, but some may be more complicated operations requiring data from a number of tables and a degree of coding to produce the resulting fabricated dataset. I then have transactional requirements which may require multiple tables to be updated as a result of a specific method requirement.

I started by creating an “entity” object which contained multiple methods relating to a common theme. I might have a Customer entity object or a Supplier entity object each of which contains a bunch of static methods relevant to that particular entity. Very quickly I found that each entity object requires lots and lots of methods, and it all starts to get a bit complicated from a coding point of view ( you end up with hundreds and hundreds of lines of code ). It is logical however to be able to call something like: Customer.GetOpenOrders(), or Customer.GetOrdersShipped().

I now wonder if I should have a command object for each requirement. In other words I have one object that performs a single function such as the GetOpenOrders() requirement, and another one to perform the GetOrdersShipped() requirement. This is much cleaner from a coding perspective but will result in me having hundreds of command objects.

I wondered if anyone could offer some suggestions of how they have tackled this issue and what works best and is most scalable...?

Thanks,

Nick

rsbaker0 replied on Friday, July 24, 2009

One technique I can suggest is that you can just implement a common base class so that all that is really different is the parameter passed to the command (if any) and the server side processing.

You can also contruct simple derived classes that basically just implement the server side processing (even via a delegate).

So, what you end up with is a large number of methods to be executed by your commands and very simple CommandBase-derived class implementations to execute them.

I can post samples if you want to see this.

NickTaylor replied on Saturday, July 25, 2009

Hi,

Yes that would be great thanks, I would be very interested to see how you have structured this...

Many thanks,

Nick

whelzer replied on Saturday, July 25, 2009

We had/have a very similar situation.

In a fairly large financial application we have a requirement to have numerous currency lists (mostly for combobox population) , ie a list of currencies (ccyId, ccyName), we have a CurrencyLst object, that has many factory methods and many DP fetches, so we'll have GetCcysByStatus, GetCcyByTradeType, GetCcyBySomethingElse...

Sounds to me that you merely need a CustomerList object that has many factory methods and many Dp_Fetches (getCustomersBySales, getCustomersByWhatever, what happens inside the DP_Fetches is entirely up to you, get data from main Db, get data from xml file, get data from static flat file system, , a combination of all these - it shouldn't (and doesn't) matter where the data comes from.

You probably end up with more code (more methods anyway) doing this but you get a very clean, easy to expand, easy to use solution.
ie I need a list of currencies - use CurrencyList object - if my particular list/method is not there - just create it - slots in no bother.

(We code gen 90% of the csla stuff - meaning we just build the Dp_fetch code manually which would typically be a new stored proc and DAL code.)

Edit - I ended going down this route based on this thread  http://forums.lhotka.net/forums/thread/25488.aspx

rsbaker0 replied on Saturday, July 25, 2009

Yes, if you're just fetching an object, no matter how complex internally, I think this is best done via a BusinessBase derived class (or one of xxxxListBase classes if you are fetching a collection).  Then you can implement static factory methods that execute the appropriate DataPortal_Fetch.

On the other hand, complicated server side updates can be done either as CommandBase or BusinessBase derived classes. If input from the user is expected, a BusinessBase class is better because it is bindable and has validation rule capability. CommandBase classes have neither. You can do whatever you want server side in DataPortal_Execute method of a CommandBase or DataPortal_Update of a BusinessBase.

Here is a sample command implementation. We do internal transaction management, so think of TransactionContext as just something that can Begin/Commit/Rollback and knows if a transaction in progress or not.

Base Class (the "harder" one)

using System;

namespace Csla.WORMapper
{
    /// <summary>
    /// Execute a command with a generic argument in a database transaction, automatically enlisting in
    /// current one if active
    ///
    /// Usually, derived classes need only override the Execute(TransactionContext context) method
    /// </summary>
    /// <typeparam name="T">A class that inherits from <see cref="TransactionalCommand{T,V}"/>.</typeparam>
    /// <typeparam name="V">An argument of any type.</typeparam>
    [Serializable()]
    public class TransactionalCommand<T, V> : CommandBase where T : TransactionalCommand<T, V>
    {
        protected V _arg;
        protected string _databaseKey;

        protected TransactionalCommand()
            : this("Base")
        {
        }

        protected TransactionalCommand(string databaseKey)
        {
            _databaseKey = databaseKey;
        }

        public static V Execute(V arg )
        {
            return Execute(arg, "Base");
        }

        bool _autoBeginTrans = true;

        public virtual bool AutoBeginTrans
        {
            get { return _autoBeginTrans; }
            set { _autoBeginTrans = value; }
        }

        public V Argument
        {
            get { return _arg; }
        }
        public static V Execute(V arg, string databaseKey)
        {
            // Must retrieve via data portal
            TransactionalCommand<T, V> command = Activator.CreateInstance<T>();
            command._arg = arg;
            command._databaseKey = databaseKey;
            return DataPortal.Execute<TransactionalCommand<T,V>>(command)._arg;
        }

        protected override void DataPortal_Execute()
        {
            TransactionContext.ExecuteInTransaction(_databaseKey, Execute, AutoBeginTrans);
        }

        protected virtual void Execute(TransactionContext context)
        {
            throw new System.NotImplementedException("Method Execute() must be implemented in derived class");
        }
    }
}

-----------------

Derived classes can be very simple and just implement and override of Execute(). Here is a command nested in a class I have called ReceiveOneItem that sends the item to inspection:

The command argument for the base class can be anything, but in this case it's an actual BO that implements a normal save operation (the receive item transaction). In this case I don't want to save it normally but instead do a different transformation on it on the server (send it to inspection where someone can verify it's condition and either receive it or reject it).

As you can see, the derived command implementation is trivial. It just calls a method on the argument. You can compose these yourself almost abitrarily.

        [Serializable]
        private class SendToInspectionCommand : Csla.WORMapper.TransactionalCommand<SendToInspectionCommand, ReceiveOneItem>
        {
            protected override void Execute(Csla.WORMapper.TransactionContext context)
            {
                _arg.ToInspectOneItem(context);
            }
        }

        internal void ToInspectOneItem(Csla.WORMapper.TransactionContext transaction)
        {
 ..
 .. DO WORK HERE
 }

 

 

rsbaker0 replied on Saturday, July 25, 2009

Yes, if you're just fetching an object, no matter how complex internally, I think this is best done via a BusinessBase derived class (or one of xxxxListBase classes if you are fetching a collection).  Then you can implement static factory methods that execute the appropriate DataPortal_Fetch.

On the other hand, complicated server side updates can be done either as CommandBase or BusinessBase derived classes. If input from the user is expected, a BusinessBase class is better because it is bindable and has validation rule capability. CommandBase classes have neither. You can do whatever you want server side in DataPortal_Execute method of a CommandBase or DataPortal_Update of a BusinessBase.

Here is a sample command implementation. We do internal transaction management, so think of TransactionContext as just something that can Begin/Commit/Rollback and knows if a transaction in progress or not.

Base Class (the "harder" one)

using System;

namespace Csla.WORMapper
{
    /// <summary>
    /// Execute a command with a generic argument in a database transaction, automatically enlisting in
    /// current one if active
    ///
    /// Usually, derived classes need only override the Execute(TransactionContext context) method
    /// </summary>
    /// <typeparam name="T">A class that inherits from <see cref="TransactionalCommand{T,V}"/>.</typeparam>
    /// <typeparam name="V">An argument of any type.</typeparam>
    [Serializable()]
    public class TransactionalCommand<T, V> : CommandBase where T : TransactionalCommand<T, V>
    {
        protected V _arg;
        protected string _databaseKey;

        protected TransactionalCommand()
            : this("Base")
        {
        }

        protected TransactionalCommand(string databaseKey)
        {
            _databaseKey = databaseKey;
        }

        public static V Execute(V arg )
        {
            return Execute(arg, "Base");
        }

        bool _autoBeginTrans = true;

        public virtual bool AutoBeginTrans
        {
            get { return _autoBeginTrans; }
            set { _autoBeginTrans = value; }
        }

        public V Argument
        {
            get { return _arg; }
        }
        public static V Execute(V arg, string databaseKey)
        {
            // Must retrieve via data portal
            TransactionalCommand<T, V> command = Activator.CreateInstance<T>();
            command._arg = arg;
            command._databaseKey = databaseKey;
            return DataPortal.Execute<TransactionalCommand<T,V>>(command)._arg;
        }

        protected override void DataPortal_Execute()
        {
            TransactionContext.ExecuteInTransaction(_databaseKey, Execute, AutoBeginTrans);
        }

        protected virtual void Execute(TransactionContext context)
        {
            throw new System.NotImplementedException("Method Execute() must be implemented in derived class");
        }
    }
}

-----------------

Derived classes can be very simple and just implement an override of Execute(). Here is a command nested in a class I have called ReceiveOneItem that sends the item to inspection:

The command argument for the base class can be anything, but in this case it's an actual BO that implements a normal save operation (the receive item transaction). In this case I don't want to save it normally but instead do a different transformation on it on the server (send it to inspection where someone can verify it's condition and either receive it or reject it).

Invocation is simple: (ReceiveOneItem implements a SendToInspection method that calls the command on itself and returns the transformed object)

        public ReceiveOneItem SendToInspection()
        {
            return SendToInspectionCommand.Execute(this);
        }

Below, the derived command class implementation is trivial. It just calls a method on the argument. You can compose these yourself almost abitrarily, and your objects can support either simple server side operations or different flavors as needed.

        [Serializable]
        private class SendToInspectionCommand : Csla.WORMapper.TransactionalCommand<SendToInspectionCommand, ReceiveOneItem>
        {
            protected override void Execute(Csla.WORMapper.TransactionContext context)
            {
                _arg.ToInspectOneItem(context);
            }
        }

        internal void ToInspectOneItem(Csla.WORMapper.TransactionContext transaction)
        {
         ..
         .. DO WORK HERE
        }

 

 

Copyright (c) Marimer LLC