(Probably) an Elementary question

(Probably) an Elementary question

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


Jav posted on Tuesday, July 18, 2006

Class A
         Inherits Csla.BusinessBase
' Contains the standard code - with Protected Constructor

End Class

Class B
         Inherits A
' Declares additional Instance Variables

Private Sub New()
End Sub

Public Shared NewB(..........) As B 
         ' The following does not work - generates runtime error           
         Return CType(A.NewA(...........), B)
End Sub

My class A is a Root object with a lot of children.  I thought I could subclass it to offer a simpler "front" to the UI into the object hierarchy.  What would be a legal way to do it?
            

 

RockfordLhotka replied on Tuesday, July 18, 2006

You somehow need to get the type (B) into the data portal. CriteriaBase is designed for scenarios like this.

Have A declare the criteria, but inherit from CriteriaBase. Then the (protected?) factory of A needs to accept a parameter with the type of B. So A's factory might be:

Protected Shared Function GetA(objType As Type) As A
  Return DataPortal.Fetch(New Criteria(objType))
End Function

The point is, that the data portal needs to know that it should create an instance of B - that can happen either because the criteria object is nested in B, or through the use of CriteriaBase (which requires that you specify the object type when creating the criteria object).

Jav replied on Tuesday, July 18, 2006

Thanks Rocky. 
Working late?  I thought surely everyone is in bed by this time.  I will try your suggestions.

Jav

xal replied on Wednesday, July 19, 2006

Jav,
I don't thing this is a dataportal problem.

You say B inherits from A. You're trying to cast an instance of A to B but that is not possible, because A doesn't know how to be B. You can cast an instance of B to A, but not the other way around.

Try this and see where it fails:

Public Shared NewB(..........) As B 
         ' The following does not work - generates runtime error          
          Dim instance as A = A.NewA(...........)
         Return CType(instance, B)
End Sub


You can cast an object to the type of a superclass, but you can't cast an object to the type of a derived class.

Andrés

Jav replied on Wednesday, July 19, 2006

Andres,

Thanks.  I am discovering that, and also discovering many other issues.  The superclass's DataPortal methods contain code, much of which is tied to its own Type, which ends up being a problem.

I think the solution is to provide B its own DataPortal methods. I can still make the Properties and Methods of A available, as well as provide access to A's Children, to B, but the process of Object creation and acquisition, and the Factory methods, will have to be specific to B.  What do you think?

Jav

Jav replied on Wednesday, July 19, 2006

The preliminary tests show that I can create my subclass by doing the following:

1. Provide the Factory methods that create or fetch, and the DataPortal_Create and DataPortal_Fetch.  Criteria class also if needed.
2. Save method of the superclass should work fine. Also, Insert and Update do not need to be duplicated (I think)
3. The PK instance variable of superclass will need to be made Protected so it can be set in the subclass's Create
4. Make the superclass Constructor Protected.

Jav

RockfordLhotka replied on Wednesday, July 19, 2006

You may want to read this article about inheritance options

http://www.lhotka.net/Article.aspx?id=e130b265-15cb-453d-9719-d5a944385fd3

Jav replied on Wednesday, July 19, 2006

Rocky,

I started down this path reading all the discussion about the data and the behavior, and trying to figure out if there is some neat way to rearrange my classes. 

Like most other code generators, I am perfecly happy to have a single class totally in-charge of a given DataTable - reading, writing, and validating the data. Why not?  But I thought that if I could interpose another "class" between the Root of a hierarchy on the one hand and the UI on the other - a class that is more behavior-oriented and not so much data-oriented - then I could use the same hierarchy in different scenerios by simply interposing a different class.

I have not tested it yet, but I am thinking if it might not be possible for the subclass to have the Factory methods as usual, but to call the base class to populate its data from within the DataPortal methods.  At that point the SubClass will already be instantiated and the only question will be of its access to some method of the base class.  This is probably not too different from a Collection calling its Child object to load itself.

Jav

pelinville replied on Wednesday, July 19, 2006

This is what I do and is basicaly what Dollard suggests in her book... I think. Maybe I got this from Rocky's site? 
 
 Maybe it will help.
 
'---The Following Is code Generated and is for 1.x CSLA--
 
Public MustInherit BaseClassA
    Inherits BusinessBase
   Protected Sub New()
   End Sub
 
   Public Shared Function GetClass() as ClassA
      Dim Obj as ClassA
      Obj = DirectCast(DataPortal.Fetch(New Criterea()), ClassA)
      Obj.Validate
      Obj.MarkOld
      Return Obj
   End Function
 
   Public Shared Function NewClassA() as ClassA
      Dim Obj As New ClassA
      Obj.MarkNew
      return Obj
   End Function
 
   'This one is so the a collection or Root can create them
   'I have another one that also takes a dataRow as an argument
   'so that I can work either.
   Friend Shared Function SetClassA(dr as IDataReader) as ClassA
      Dim Obj As New ClassA
      Obj.SetByDataReader(dr)
      Obj.MarkOld
      Obj.MarkAsChild
      Return Obj
   End Function 
 
   Public Class Criteria
         Inherits CriteriaBase
         Public Sub New()
         End Sub
   End Class
 
End Class
 

'-------This is Done by Hand
Public Class ClassA
   Inherits BaseClassA
  
   Protected Friend Sub New()
      'This has to be Friend so BaseClassA can create it.
   End Sub
 
   'If I need more Factory Methods
   Public Shared Function AnotherGetClassA(inpute as SomeType) as ClassA
      Dim Obj as ClassA
      Obj = DirectCast(DataPortal.Fetch(New Criterea(someType)), ClassA)
      Obj.MarkOld
      Obj.Validate
      return Obj
   End Function

End Class
 
 
The key is that in the generated base class you assume that there will be a subclass and have the factory methods return the Sub type.  BaseClassA cannot be created.
 
A draw back is that the Constructor in ClassA is Friend so the Business object coder has to be carefule and not ever call it in another class.  But outside the component it is not accessable so it is a minor thing.

Copyright (c) Marimer LLC