Stuck /w Inheritence and ObjectFactory issue (so close)

Stuck /w Inheritence and ObjectFactory issue (so close)

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


Jack posted on Friday, December 19, 2008

I've been scouring the forums for hours and tweaking and re-compiling and I'm going crazy.  It feels like I've done everything right but I'm still having an issue creating my derived class /w most of the logic in a base class.  I've gone in circles and have almost solved it but I thought I would put it in all in post incase some other poor sap ends up down the same path.

I'll be the first to admit generics are new to me but I'm trying to keep it simple.  I have the sense the BBLists are a little more strict.

I have three main goals and 1 constraint:

1) one stay as true to the framework as possible for future maintenance
2) add two layers on top of the CSLA framework - one for company, one for app for future proofing and when I have a better understanding
3) put as much logic in the base classes (complemented by codeGen) and then have a derived class for the UI.  I don't really see the need for another layer.

4) Constraint - this particular UseCase is the most complex and I need to retrieve all the data at once for several BO's and BOLists so I'm using a ObjectFactory

So far everything at the base class level is working in terms of the create/fetch, however when I try to create the derived UI class by casting from my base class I get a runtime InvalidCastException exception.  

From all the reading and playing (I got it to work but I butchered many of the CSLA concepts) I realized the answer is something along the lines of 'You need to create the DataEntrySession from its own criteria etc etc)

I have done the following:


2) Generic classes for my company library and my app libraries.

    public abstract class AgcBusinessBase<T> : BusinessBase<T>      where T : AgcBusinessBase<T>
    public abstract class EpmBusinessBase<T> : AgcBusinessBase<T>   where T : EpmBusinessBase<T>

    public abstract class AgcBusinessBase<T> : BusinessBase<T>      where T : AgcBusinessBase<T>
    public abstract class EpmBusinessBase<T> : AgcBusinessBase<T>   where T : EpmBusinessBase<T>

    &

    public abstract class AgcBusinessListBase<T, C> : AgcBusinessListBase<T, C>
        where T : AgcBusinessListBase<T, C>
        where C : AgcBusinessBase<C>

    public abstract class EpmBusinessListBase<T, C> : AgcBusinessListBase<T, C>
        where T : EpmBusinessListBase<T, C>
        where C : EpmBusinessBase<C>
        
3) New base class using an objectFactory

    [Csla.Server.ObjectFactory("Epm.Library.DataEntry.DataEntryObjectFactory, Epm.Library")]
    public class DataEntrySessionBase : EpmBusinessBase<DataEntrySessionBase>
    
    protected static DataEntrySessionBase GetDataEntrySessionBase(int dataSessionId)
    {
        return DataPortal.Fetch<DataEntrySessionBase>(new SingleCriteria<DataEntrySessionBase, int>(dataSessionId));
        }
        
4) New derived class (Concrete)

    public class DataEntrySession : DataEntrySessionBase

        public static DataEntrySession GetDataEntrySession(int dataSessionId)
        {
        // *** this is where my cast exception happens ***
            //return (DataEntrySession)DataEntrySessionBase.GetDataEntrySessionBase(dataSessionId);

        // proper call
        return DataPortal.Fetch<DataEntrySession>(new SingleCriteria<DataEntrySession, int>(dataSessionId));
        }
    
    
5) In my windows form I'm populating my local dataEntrySession object to do databinding:

    dataEntrySession = DataEntrySession.GetDataEntrySession(12345);
    
So I was able to make a few tweaks but I'm not really liking where I ended up - I changed the GetDataEntrySession in the derived class so that it calls the DataPortal_Fetch and I end up in my ObjectFactory_Fetch.

This still didn't help as it had been calling the base.NewBase().  I removed that call and replaced it with something using reflection that I pulled out of the forums:

     object dataEntrySession = Activator.CreateInstance(criteria.ObjectType, new object[] {criteria.Value});
     
The problem with this is that it requires a non-private constructor as the ObjectFactory is its own class and that seems to violate the CSLA methodologies.


Long story short - I have some inklings why I can't cast to get someDerivedBO = (DerivedBO)BaseBO.GetBaseBO(12345) but I don't really understand why not.  I thought maybe it was to do with generics but I'm not so sure now.

I guess what I need help with is how to actually properly create or get an instatiated DerivedBO into the ObjectFactory for the base class.  

1) Maybe it is as simple as just deriving another objectFactory from the base class?  
2) The ObjectFactory can create either a BaseClass or a DerivedClass based on the criteria object?  That seems almost wrong though..
3) Some of way of once I'm in the ObjectFactory of getting back to the calling class to instiantiate?

Help, I'm so close :-)

Thanks

jack

ajj3085 replied on Friday, December 19, 2008

Your factory methods must be declared on your ultimate subclass.  A DerivedBo is a BaseBo, but a BaseBo isn't necessarly a DerivedBo... it could be a Derived_2Bo, and there's no way BaseBo has enough information to instanciate Derived_2BO (or DerivedBo, for that matter).

Csla doesn't impose this restriction though, it's just how object oriented design works.

HTH
Andy

Jack replied on Friday, December 19, 2008

Yeah I got through that part - I was so concerned with generics and inheriting problem /w respect to the CSLA that I wasn't paying attention.

How would you recommend solving my final issue - how to actually instantiate the derivedBO from the ObjectFactory.  For now I just quickly created a derived ObjectFactory and created a stub in both the base/descendant
   
    object GetNewBO( ) which calls either NewBaseBO( ) or NewDerivedBO( )

It seems to work and be fairly clean but I don't want it to bite me in the ass down the road.

thx

Jack

ajj3085 replied on Friday, December 19, 2008

I've not looked at the ObjectFactory yet, so I don't know if I can help you specifically.  I will say that at some point something needs to decide which factory method to call (Dervired or Base).  So there will probably have to be code somewhere that makes the decision.

FrankM replied on Friday, December 19, 2008

Keep adding generic in your DataEntrySessionBase<T>, then
 public class DataEntrySession : DataEntrySessionBase<DataEntrySession>

in csla, whenever you want to name a class as something base, you very likely need to pass inheritor's type back to this base to take advantage of base DP methods.

Jack replied on Friday, December 19, 2008

Frank,

thanks for you input - I thought I read some posts where Rockford recommending creating a concrete class as high as possible in the inheritance chain? 

I don't really see any need (other than maybe something specific for a different UI ) that I would want to derive any further?

Or are you saying keep everything generic as long as possible?  I'm not sure I really understand what the benefit for me is?

thanks

jack

JoeFallon1 replied on Friday, December 19, 2008

someDerivedBO = (DerivedBO)BaseBO.GetBaseBO(12345)

Your Base BO can have factory methods in it - but only if they use the final type! Not the Base type.

I code generate all my Base classes and then inherit from them. The final types have very little code in them. Only stuff I need to override.

So your code above should be:

someDerivedBO = DerivedBO.GetDerivedBO(12345)

even though it is located in your Base class.

If you are bothered by the fact that it is inthe wrong level then you have to remove the factory methods from base and push them down into the derived class instead. ("Where they belong").

The disadvantage to that is you are cluttering the empty final type with code that is easily generated - no need to hand craft it.

Your call.

Joe

 

Jack replied on Friday, December 19, 2008

I'm not bothered just frustrated :-)

So are you saying the base class should not have factory methods?  or that you codeGen it all and then override the factory method in the derived class? (which I've now done).  I'm a touched confused by your (*where it should be*) comment.

I've done:

BaseBO -> GetBaseBO -> BaseFactoryObject -> Fetch -> GetNewBO -> FetchData

DerivedBO -> GetDerivedBO -> DerivedFactoryObject -> BaseFactoryFetch -> DerivedGetNewBO -> FetchData.

So I basically override the GetBaseBO and added a derivedFactoryObject with a overrideed GetNewBO so that the baseFactoryObject can fetch into a derivedBO.

Make sense?  I don't mind it.  I have to hand-code the Fetch anyways so I'm only adding have dozen lines to the derived classes.

JoshL replied on Friday, December 19, 2008

Hmm... I use static factory methods in base classes all the time, and haven't had trouble using them. At the same time, I don't use ObjectFactory. Perhaps it has code that relies on a factory method implemented at the most-derived level, rather than walking the inheritance stack looking for a static method.

So long as the factory on your base class returns T (T being defined as your ultimate sub-class), it should work from a language perspective...

Jack replied on Friday, December 19, 2008

JoshL:
Hmm... I use static factory methods in base classes all the time, and haven't had trouble using them. At the same time, I don't use ObjectFactory. Perhaps it has code that relies on a factory method implemented at the most-derived level, rather than walking the inheritance stack looking for a static method. So long as the factory on your base class returns T (T being defined as your ultimate sub-class), it should work from a language perspective...


My baseClass factory method isn't returning T, it is returning baseClass. 

I think I'm maybe trying to do too much in the base classes.  Things are getting worse now as I start trying to expose BOLists to databinding. 


JoeFallon1 replied on Sunday, December 21, 2008

Both Josh and I have tried to tell you that your Base class factory mnethopds *must* return T - the ultimate final type - *not* the base type.

My other comment about "where they belong" is due to the fact that if you read all the code in the base class it looks funny to see the final type as the return value of your factory methods. You might think " that code does not belong here - it belongs in the final type." When I code gen my classes I leave the factory methods with the final type in the generated level. That way I do not have to write them in the final type which is where my hand coded stuff goes. It makes it cleaner for me - though it could be slightly confusing - as this thread has demonstrated.

Bottom line:

Your code above should be:
someDerivedBO = DerivedBO.GetDerivedBO(12345)
*even though it is located in your Base class*.

Joe

 

 

Jack replied on Monday, December 22, 2008

Joe,

 

Thank you for clarifying – It is indeed confusing and I just wanted to clarify that was exactly what you were saying.

 

I will take you suggestion under consideration – It does seem like a different approach and perhaps as I add more and more codegen steps I will see that is a technique that will work for me (it seems almost like cheating J).

 

Thanks

 

Jack

 

From: JoeFallon1 [mailto:cslanet@lhotka.net]
Sent: Sunday, December 21, 2008 12:43 PM
To: jaddington@alexandergracie.com
Subject: Re: [CSLA .NET] Stuck /w Inheritence and ObjectFactory issue (so close)

 

Both Josh and I have tried to tell you that your Base class factory mnethopds *must* return T - the ultimate final type - *not* the base type.

My other comment about "where they belong" is due to the fact that if you read all the code in the base class it looks funny to see the final type as the return value of your factory methods. You might think " that code does not belong here - it belongs in the final type." When I code gen my classes I leave the factory methods with the final type in the generated level. That way I do not have to write them in the final type which is where my hand coded stuff goes. It makes it cleaner for me - though it could be slightly confusing - as this thread has demonstrated.

Bottom line:

Your code above should be:
someDerivedBO = DerivedBO.GetDerivedBO(12345)
*even though it is located in your Base class*.

Joe

 

 



Jack replied on Monday, December 22, 2008

For the next struggling person coming along I did some more searching and this is really ultimately what I’m trying to achieve – my current 2nd layer of inheritance soley for the UI is the problem.

 

http://forums.lhotka.net/forums/thread/17974.aspx

 

 

 

From: JoeFallon1 [mailto:cslanet@lhotka.net]
Sent: Sunday, December 21, 2008 12:43 PM
To: jaddington@alexandergracie.com
Subject: Re: [CSLA .NET] Stuck /w Inheritence and ObjectFactory issue (so close)

 

Both Josh and I have tried to tell you that your Base class factory mnethopds *must* return T - the ultimate final type - *not* the base type.

My other comment about "where they belong" is due to the fact that if you read all the code in the base class it looks funny to see the final type as the return value of your factory methods. You might think " that code does not belong here - it belongs in the final type." When I code gen my classes I leave the factory methods with the final type in the generated level. That way I do not have to write them in the final type which is where my hand coded stuff goes. It makes it cleaner for me - though it could be slightly confusing - as this thread has demonstrated.

Bottom line:

Your code above should be:
someDerivedBO = DerivedBO.GetDerivedBO(12345)
*even though it is located in your Base class*.

Joe

 

 



Copyright (c) Marimer LLC