Derived classes and fetching data.

Derived classes and fetching data.

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


preludecrazy posted on Friday, March 21, 2008

Hi.  I am going to write some classes using CSLA 3.03, but before I do, I have a question with regards to the best solution...  I've tried to keep my question a simple as possible by omiting most of my data members.

I will write a derived...:

Class (class Order : BusinessBase<Order>) containing 'OrderID' and 'CompanyID' data members.

Collection (class OrderCollection : BusinessListBase<OrderCollection, Order>).  The DataPortal_Fetch(Criteria criteria) method will populate the collection will order IDs and company IDs from my orders database.

Class (class LiteCompany : BusinessBase<LiteCompany>) containing 'CompanyID' and 'CompanyName' data members.

Collection (class LiteCompanyCollection : BusinessListBase<LiteCompanyCollection, LiteCompany>).  The DataPortal_Fetch(Criteria criteria) method will populate the collection will company IDs and names from my companies database.

Class (class Company : LiteCompany) containing a 'OrderIDCollection' data member.

Collection (class CompanyCollection : LiteCompanyCollection).

So by creating an instance on CompanyCollection, I'll have a collection of companyIDs and names, also containing a collection of order IDs against that company ID.

I have done it like this because sometimes I'll want a collection of companies without a collection of order IDs.

In the DataPortal_Fetch method in my CompanyCollection, I presume I should be (indirectly) getting the DataPortal_Fetch method in LiteCompanyCollection to populate its data members, then just populate the OrderIDCollection afterwards - presumably the same way, by (indirectly) getting the DataPortal_Fetch method in the OrderCollection to populate its data members?

Is this the best/correct approach?  Rather duplicating most of the code in the DataPortal_Fetch methods?  If yes, I was wondering what the best approach is to casting my LiteCompanyCollection to my CompanyCollection?

Thanks., Jason.

tmg4340 replied on Friday, March 21, 2008

Maybe I'm missing something here, but I wouldn't do it this way.

I don't think that inheriting CompanyCollection from LiteCompanyCollection is going to help you much.  For starters, you're always going to have to cast the objects coming out of your CompanyCollection, since its definition is to return a LiteCompany object.  I don't think the indexer methods are overridable, so it isn't something you can encapsulate within your CompanyCollection.

Beyond that, remember that the standard collection-class pattern takes the DataReader and passes it into the child object that it creates through a factory method, letting said child object populate itself.  You can build that pattern into a virtual method that subclasses of LiteCompanyCollection could override, and every subclass would have to override that method and return the type of subclass that you want to put into the collection.  But you don't get much protection in using the class, as your overridable method has to be virtual, even though you want to require subclasses to override it.  Plus, you'll end up building up a lot of static methods on your subclasses, since it's the static methods that create and populate the class instance.  You can't mark static methods as overridable, so you can't keep subclasses from calling the wrong static method.

While it's perfectly fine to have Company inherit from LiteCompany, I think your collection classes are going to have to look like this:

class LiteCompanyCollection : BusinessListBase<LiteCompanyCollection, LiteCompany>

class CompanyCollection : BusinessListBase<CompanyCollection, Company>

While they would share some DP_ code, you can probably factor that out into a separate class if you want.

If I've totally missed the mark here, let me know what I'm not following.

- Scott

preludecrazy replied on Sunday, March 23, 2008

tmg4340:
While it's perfectly fine to have Company inherit from LiteCompany, I think your collection classes are going to have to look like this:

class LiteCompanyCollection : BusinessListBase<LiteCompanyCollection, LiteCompany>

class CompanyCollection : BusinessListBase<CompanyCollection, Company>

While they would share some DP_ code, you can probably factor that out into a separate class if you want.

Thanks Scott.  I started to write the classes last night before I saw your reply, and hit the problem inheriting from LiteCompanyCollection! :), and realised I had to change it to exactly what you said.

Thanks.

preludecrazy replied on Monday, March 24, 2008

Hi (Scott).

I managed to get my inherited properties to populate via reflection.  I hadn't used reflection before, so I might be doing something stupid, or this approach might be overkill or just plain wrong!, but its currently working, so I'll use it for now and see how it holds out while I write the rest of my app.

Basically, I'm calling Company.GetCompany(LiteCompany objLiteCompany) etc, in CompanyCollection.DataPortal_Fetch, and my Company.Fetch method looks like this:

private void Fetch(LiteCompany myObject)
{
   MemberInfo[] myMembers = myObject.GetType().GetMembers();
   foreach (MemberInfo myMember in myMembers)
   {
      Object[] myAttributes = myMember.GetCustomAttributes(true);
                
      foreach (object myAttribute in myAttributes)
      {
         if (myAttribute is MyDataMemberAttribute)
         {
            if (((MyDataMemberAttribute)myAttribute).IsMyProperty)
            {
               PropertyInfo[] thisProperties = this.GetType().GetProperties();
               foreach (PropertyInfo thisProperty in thisProperties)
               {
                  if (thisProperty.Name == myMember.Name)
                  {
                     PropertyInfo myObjectProperty = myObject.GetType().GetProperty(myMember.Name);
                     thisProperty.SetValue(this, myObjectProperty.GetValue(myObject, null), null);
                     break;
                  }
               }
            }
         }
      }
   }
   
MarkOld();
}

I've created a MyDataMemberAttribute with a 'IsMyProperty' property/constructor parameter, so I've just put [MyDataMemberAttribute(true)] above every property in LiteCompany that I want inherited classes to populate via reflection.

Thanks.

Copyright (c) Marimer LLC