On Apr 23, 2009, at 4/236:32 PM , Aristedes Maniatis wrote:


On 24/04/2009, at 9:17 AM, Robert Zeigler wrote:

So, I was playing around a bit with the "is abstract" flag on abstract entities.
I confess that it didn't quite work the way I thought it would.
For one, the superclass was abstract, but not the subclass.

That is the common situation when you want horizontal inheritance. [1]

Right, which is why I'm surprised at the current generated classes, but I need to be more specific.

I have:

                            Entry (abstract)
ProjectNote (concrete)  ProtocolRun(concrete)

So I checked the "isabstract" for Entity. The result of class generation was:

in package xxx.auto:
public abstract class _Entry{}
public class _ProjectNote{}
public class _ProtocolRun{}

in package xxx:
public class Entry{} //<-- this is what I found surprising
public class ProjectNote{}
public class ProtocolRun{}

I expected the Entry subclass of _Entry, and superclass of the other two concrete classes to be abstract. Instead, only the cayenne-"managed" superclass was abstract. It seems like there's very little point to that: nobody is going to try to directly instantiate _Entry, anyway. And I can't put abstract methods that subclasses should implement into _Entry, since they'll be lost on class regeneration. I guess it's a matter of expectations: by checking "isabstract", I expect cayenne to treat that object entity as abstract... and not try to instantiate it. :)


I went ahead and made the subclass abstract. Which raises the second issue. I have two obj entities entities extending the "abstract" superclass, using a single discriminator column. I went to query the base class (ala: select e from Entry e), and the query failed, due to the inability to instantiate an instance of Entry. Evidently, cayenne is trying to instantiate all of the subclasses instances as instances of the superclass. Shouldn't cayenne be instantiating the subclasses?

EOF has a switch for this called something like 'deep object resolution'. That is, when you query Artist.class, should you get back a list of Painter.class, Photographer.class, etc object (as you are expecting), or get back a list of Artist objects. Each can be useful in different situations, particularly since just returning Artist objects means less work for the database (fewer JOINs).

Obviously if your query was for Painter.class then you will only get Painter objects back.

Put another way, what is the technical reason that cayenne /isn't/ instantiating the subclasses as instances of the subclasses? Given the potential of polymorphism, it seems like instantiating as the superclass, even if the superclass is concrete, is incorrect behavior? Just trying to clarify, here. I'll be digging through the code to try to understand the specifics of how cayenne handles inheritance, but, any pointers appreciated.

I think ultimately we need both behaviours.


Fair enough that, for performance reasons, you might want only the superclass. But then... if you're using horizontal inheritance ("table per concrete class"), for example, you already need to fetch from both tables if you perform a query for the superclass; I'm trying to think of an instance when you would be performing a superclass query and / not/ have the type information at hand... ok, vertical inheritance, you might not have the type information. :) In terms of additional joins to fetch additional information... we already have lazy loading of relationships; it seems like it should be possible to lazy-load the attributes, as well, at least for queries on the superclass, saving the hassle of additional joins... I think the only place where you would have additional joins is vertical inheritance, anyway... and, I suppose, if a subclass has a flattened property not present in the parent class.

Anyway, not opposed to keeping the option of the current behavior, but definitely +1 for resolving to the subclass level. It'll be necessary to properly support horizontal inheritance.

Robert

Reply via email to