8. Working with Heterogeneous Collections and References
Contents
Heterogeneous collections are collections that can hold objects of multiple classes. The most common example of a heterogeneous collection is a collection that holds all subclasses of a base class. Heterogeneous collections can be defined using the mapping tool as part of an application schema. However, in the case of heterogeneous collections based on a base class or common interface there is no need to do so, as VBSF automatically creates heterogeneous collections at runtime for all base classes and interfaces that are referenced by the persistent classes in your schema. The only time you need to explicitly define a heterogeneous collection is when the classes in the collection are not related by a common superclass or interface.
To retrieve objects from a heterogeneous collection you must specify the name of the base class, common interface, or the name of the collection when invoking the standard get and list methods of the Database and OCollection classes. If VBSF automatically created the collection because one was not explicitly defined, then the name of the collection will be the fully qualified abstract class or interface name suffixed by the string 'Col'.
For example, if we have an abstract Customer
class from which the Person and Organization concrete classes descended, then we
would use the statement below to retrieve
all concrete descendants of Customer:
Object[] all = db.get(Customer.class);
The above statement would retrieve both Person and Organization
objects. Queries can also be formulated using the base class name:
OQuery qry = new OQuery(Customer.class);
qry.add(..);
Object[] all = qry.execute(db);
When executing queries on heterogeneous collections, you should use only query parameters
for attributes common to all the classes in the collection.
In the above examples, if the Customer
class was a concrete class instead of abstract, then the above statements would
only retrieve objects of type Customer. In
that case, if we wanted to retrieve all objects of type Customer,
Person and Organization, then we would have to use the
heterogeneous collection name as argument to the get method. Assuming that VBSF
automatically created the collection, then the collection name would be the
fully qualified base class name suffixed by the string 'Col', as shown in the
example below:
Object[] all = db.get(Customer.class.getName() + "Col");
The Database and OCollection
classes also provides the following additional methods specific to heterogeneous
collections:
Object[] getForClass(String hCollName,String className);
Object[] getForClass(String hCollName, String className, BOP_Query query);
BORandomEnumeration getEnumerationForClass(String hCollName, String className);
BORandomEnumeration getEnumerationForClass(String hCollName, String className, BOP_Query
query);
Object[] listForClass(String hCollName, String className);
Object[] listForClass(String hCollName, String className, BOP_Query query);
BOEnumeration listEnumerationForClass(String hCollName, String className);
BOEnumeration listEnumerationForClass(String hCollName, String className, BOP_Query
query);
The above methods allow you to retrieve from a heterogeneous collection only objects of
the supplied class name. For example, to retrieve only Person
objects from the Customers collection, we would use
the following statement:
Object[] allPersons = db.getForClass(Customer.class.getName(), Person.class.getName());
In the event that multiple objects of different classes that belong to the same
heterogeneous collections have the same ID, and there is no explicit filter
column, a heterogeneous collections will only return objects of the most concrete subclass. The only time multiple objects with the same ID may be returned is when the objects with the same ID do not have an inheritance relationship.
A heterogeneous reference points to either a base class or an interface. If
it points to a base class, it can reference an object of any type that is a
subtype of the base type. If it points to an interface, it can reference an
object of any type that implements that interface. Heterogeneous references return the most concrete class that matches the
referenced ID, so a filter column is not necessary. However, a filter column does avoid querying the tables of all subtypes searching for the most concrete
match. If you know the actual expected subtype, then you can also call the OReference.get(String
className) or Database.getReference(Object holder, String refName, String
className) methods, where className
is the fully qualified name of the expected subtype.
The vposdemo and vshapesdemo sample applications provide many examples dealing with
heterogeneous collections and references.