Abstract class design & development

Abstract class design & development

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


msrs_it posted on Saturday, September 24, 2011

Hi,

I have an abstract class Company and derived classes AutoDealer, Fleet, etc...

There exists differences in autodealer and fleet companies. Both have some common data and functionality which I want to place in the abstract class. For example, both the companies may or may not add their bank account details in to the system, which depends on the type of account they've chosen. Let us say standard and preferred accounts. The preferred account user needs to enter their bank account details in to system. The system has to allow up to 3 bank accounts for each company in which one should be the default account.

The autodealer requires additional data and behavior like dealership license details and purchase of vehicles. The fleet has a different behavior that required to track transport booking and delivery details.

I've declared the required common company properties in the abstract class. I was stuck with declaring the EditableChildList property of CompanyBankAccountsList in company abstract class. And CompanyBankAccount is declared as EditableChild having problem in declaring the data access methods too. Because this Editable Child object requires parent object as a parameter to insert and update methods.

Can anybody help me in providing an example code for this situation like this?

 

Thanks & Regards,

SreeRam.

msrs_it replied on Saturday, September 24, 2011

Hi,

Below is the data access code I've written for EditableChild object to perform insert operation. Is this works or not?

 

private void Child_Insert<T>(T company) where T: Company<T>

        {

            Child_Insert(company.Id);

        }

 

        private void Child_Insert(int companyId)

        {

            using (var ctx = LX.Dal.DalFactory.GetManager())

            {

                var dal = ctx.GetProvider<LX.Dal.ICompanyBankAccountDal>();

                using (BypassPropertyChecks)

                {

                    var item = new LX.Dal.CompanyBankAccountDto

                                   {

                                       CompanyId = companyId,

                                       BankAccountStatus = this.BankAccountStatus,

                                       AccountName = this.AccountName,

                                       AccountNumber = this.AccountNumber,

                                       AddedDate = DateTime.UtcNow,

                                       BankAccountTypeId = this.BankAccountTypeId,

                                       BankId = this.BankId,

                                       StreetAddress = this.StreetAddress,

                                       City = this.City,

                                       StateId = this.StateId,

                                       Zip = this.Zip,

                                       RoutingNumber = this.RoutingNumber,

                                       ModifiedDate = DateTime.UtcNow,

                                       IsDefault = this.IsDefault,

                                       IsDisabled = this.IsDisabled,

                                       IsNew = this.IsNew,

                                       IsDeleted = this.IsDeleted

                                   };

                    dal.Update(item);

                    Id = item.BankAccountId;

                    TimeStamp = item.LastChanged;

                }

            }

        }

 

 

Thanks & Regards

SreeRam

JonnyBee replied on Monday, September 26, 2011

Hi,

I'd remove the generic Child_Insert<T> method (and others) and just keep Child_XYZ(int companyId) methods.

In your "root"/parent object - just use the

The last one will process all child objects in managed fields in this object and call Child_XYZ with whatever parameters you add to the call.

Beware -  this requires that ALL you Chlid_Insert, Child_Update, Child_DeleteSelf methods have the same signature - with all the parameter that you add as parameters to the Update function. This is a dynamic call using MethodCaller.

msrs_it replied on Wednesday, October 05, 2011

JonnyBee

Hi,

I'd remove the generic Child_Insert<T> method (and others) and just keep Child_XYZ(int companyId) methods.

In your "root"/parent object - just use the

The last one will process all child objects in managed fields in this object and call Child_XYZ with whatever parameters you add to the call.

Beware -  this requires that ALL you Chlid_Insert, Child_Update, Child_DeleteSelf methods have the same signature - with all the parameter that you add as parameters to the Update function. This is a dynamic call using MethodCaller.

Hi Jonny,

I know that you gave reply to my second post which contains code sample I've pasted. As you said, the framework requires the DataPortal_Fetch(), Child_Fetch() or any data access method must maintain the signature to get executed at server side.

If you go through my first post I've stated the situation I'm facing in the business object design. I thought that the Company class should be declared as an abstract class which is the base class for AutoDealer and Fleet companies.

Could you please go through that post once again and suggest me weather to use abstract class or not.

However, we can remove the abstraction and can accept additional inputs like dealership license number, etc... from auto dealer by creating a custom rule and force user to enter the inputs. But how can we achieve a separate behavior (only auto dealer can purchase a vehicle) for an auto dealer. In the same way the Fleet can provide quote to the request sent by an auto dealer.

Awaiting for your reply.

Thanks & Regards,

SreeRam.

JonnyBee replied on Thursday, October 06, 2011

Hi,

abstract classes means that you cannot create an instance of that class.

You could create an abstract generic base class (ex Company<T>) and an accompanying interface class (İCompany) that you could pass to the child lists/objects (ex Child_XYZ methods).

İ am travelling home from vacation now and should be able to provide some samples tomorrow.

msrs_it replied on Thursday, October 06, 2011

Hi,

Thank you for your response. I'll wait for your examples.

For your information here i'm I'll explain my object design a little bit

Company is an abstract class and the AutoDealer and Fleet are the derived classes.

CompanyBankAccounts is an editable child class which is required to all the derived classes.

Hence I want to place this class in the abstract class (Company<T>) as a child object.

You can observe the Class Diagram Image. In that Company is having a property "BankAccounts".

The main activity of the Auto dealer is to purchase the vehicles online. Where as the Fleet will get a quote requests from other companies and will provide the quotes. On confirmation, the order will raise and vehicle will be transported by the fleet.

Both the companies Auto dealer and Fleet have some common behavior like Selling the vehicles. Which I want to implement this behavior in the base class.

Your suggestions are valuable to me. I always appreciate your help.

Thanks & Regards,

SreeRam.

JonnyBee replied on Thursday, October 06, 2011

I believe your abstract class should be something like this:

  [Serializable]
  public abstract class Company<T> : BusinessBase<T>, ICompany where T : Company<T>
  {
    #region Business Methods
 
    public static readonly PropertyInfo<int> IdProperty = RegisterProperty<int>(c => c.Id);
    public int Id
    {
      get { return GetProperty(IdProperty); }
      set { SetProperty(IdProperty, value); }
    }
 
    public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
    public string Name
    {
      get { return GetProperty(NameProperty); }
      set { SetProperty(NameProperty, value); }
    }
 
    public static readonly PropertyInfo<BankAccountList> AccountListProperty = RegisterProperty<BankAccountList>(c => c.AccountList, RelationshipTypes.Child);
    public BankAccountList AccountList
    {
      get { return GetProperty(AccountListProperty); }
      set { SetProperty(AccountListProperty, value); }
    }

And the AutoDealer like this:

  [Serializable]
  public class AutoDealer : Company<AutoDealer>
  {
    #region Business Methods
 
    public static readonly PropertyInfo<SmartDate> LicenseIssueDateProperty = RegisterProperty<SmartDate>(c => c.LicenseIssueDate, nullnew SmartDate());
 
    public string LicenseIssueDate
    {
      get { return GetPropertyConvert<SmartDatestring>(LicenseIssueDateProperty); }
      set { SetPropertyConvert<SmartDatestring>(LicenseIssueDateProperty, value); }
    }

I'd also suggest to have the DataPortal_XYZ implemented only in the inherited classes (here AutoDealer).

Ex in AutoDealer:

    [Transactional(TransactionalTypes.TransactionScope)]
    protected override void DataPortal_Insert()
    {
      // update value properties


      // update child properties       FieldManager.UpdateChildren(this);     }     [Transactional(TransactionalTypes.TransactionScope)]     protected override void DataPortal_Update()     {       // update direct properties       // update child properties       FieldManager.UpdateChildren(this);     }

Then in BankAccount you would have:

    private void Child_Insert(object parent)
    {
      var company = (ICompany) parent;
      // TODO: insert values
 
    }
 
    private void Child_Update(object parent)
    {
      var company = (ICompany)parent;
      // TODO: update values
 
    }

Did this solve your problem?

msrs_it replied on Friday, October 07, 2011

Hi,

Thanks Jonny :)

I've one more doubt. I've not used any Interface like ICompany.

But I understood that the interface helps in identifying the parent object type in the child objects.

Other than this, is anything special purpose for this interface definition (in your sense)

 

Thanks & Regards,

SreeRam.

msrs_it replied on Friday, October 07, 2011

Hi,

private void Child_Insert(object parent)
    {
      var company = (ICompany) parent;
      // TODO: insert values
 
    }
 
    private void Child_Update(object parent)
    {
      var company = (ICompany)parent;
      // TODO: update values
 
    }
Here company is not exposing any properties or methods that are declared in the base class.
Except the properties mentioned in the ICompany interface.
Any suggestions ....
Thanks & Regards
SreeRam.

JonnyBee replied on Friday, October 07, 2011

Hi,

When you use generic classes you need to:

Your child objects , ex BankAccount, should not know about AutoDealer or Supplier - only that the parent is a Company<T> that implements ICompany. .

If they need to know the parent object type then consider to make them separate objects or use a generic base class with properties like Company<T>.

lazaroms replied on Tuesday, September 03, 2013

Hi JonnyBee:

 

And how must be implemented the ICompany interface in this example?

 

Thanks,

 

Lazaro

JonnyBee replied on Tuesday, September 03, 2013

The interface must define the properties and methods that you want to expose to code that should not require knowledge of the actual inherited type. 

lazaroms replied on Tuesday, September 03, 2013

Thanks Jonny Bee.

Another question derived from this. I'm working with CSLA 4.5 in  project with Library, DAL & DalEF.

I have an abstract class: Country and two derived classes (Residence country and Destiny country)

I read your explanation in this thread and I understood it, my question is: Do we have to treat the inheritance even in the DAL & DalEF or it's just in the library?

ntimothys replied on Wednesday, January 02, 2013

I hd a similar problem - the Generics did not work out.

The base insert method was too much the same to duplicate.

 

I interfaced out the base class.

 

Child_Insert(ICompany parent)

 

Copyright (c) Marimer LLC