Forum OpenACS Q&A: Apple WebObjects
relevant tool and technology for implementing database driven web
applications and has a lot of comprehensive documentation of great
interest to anybody designing such a platform or reviewing the
I've only glanced VERY quickly through some of these and am mainly
posting this to clarify the distinction between the sort of "SQL
abstraction" provided by WebObjects and the different requirements
which I believe are relevant to the current discussion in "ACS x
For what it's worth, WebObjects, or its Enterprise version looks to
me like an excellent framework for enterprise shops that are doing
Rapid Application Development of many internal applications that need
to be accessible via the web and based on enterprise RDBMs.
This seems to me a different environment from that addressed by ACS,
where specific modules such as ecommerce are doing very specific
things that need to be highly optimized and specifically oriented
towards web use.
It looks far more than the "junk middleware" described in "The Book",
but still fundamentally unsuitable for the sorts of things OpenACS is
1. It isn't open source and doesn't work with open source RDBMs. In
fact its expensive and works mainly with expensive RDBMs (Oracle,
Sybase, Informix). There is however a generic ODBC adapter, so
presumably that could be made to work with Postgresql once it has
outer joins (planned for 7.1 or 7.2?).
2. The database independence is somewhat illusory. You end up having
to redesign the application and the database tables together anyway
and still have middleware in the way of fully optimizing an
application for a particular database or site. I can't see the
advantage in using a Java or C API for that sort of thing rather than
The following excerpts, without comment, are intended to illustrate
(2.3MB, 288 pages)
Server-specific subclasses encapsulate the behavior of database
thereby offering a uniform way of interacting with servers while still
allowing applications to exploit their unique features. For example,
Framework provides the classes OracleAdaptor, OracleAdaptorContext,
and OracleAdaptorChannel which implement the functionality specified
in the adaptor level in terms of the Oracle client libraries.
server-specific subclasses are referred to as an adaptor. For
the Oracle subclasses are collectively referred to as the Oracle
The adaptor level deals with database rows packaged as NSDictionary
objects. When an adaptor fetches from a relational database, it
the raw data in whatever form the database client libraries provide.
adaptor then packages the data in dictionaries'one per database
Each dictionary contains key-value pairs; the keys typically
the name of a column, and the key's value corresponds to the data for
column in that particular row. Going the other way, the adaptor
dictionaries into raw data that the server can accept whenever it
insert or update database rows.
The Database Level
The database level creates enterprise objects from the dictionaries
retrieved by the adaptor level. It's also where snapshotting is
Snapshotting is used by Enterprise Objects Framework to manage
updates. For caching, For updating, when an object is fetched from the
database, a snapshot is taken of its state. A snapshot'an NSDictionary
object'is consulted when you perform an update to verify that the data
in the row to be updated has not changed since you fetched the object.
The correspondence between an enterprise object class and stored
data is established and maintained in a model. A model defines, in
entity-relationship terms, the mapping between enterprise object
classes and a database. [...]
Most of the modeling classes represent components of the database-to-
While a model can be generated programmatically at run time, the most
common approach is to use the EOModeler application to create models
and store them in files. The Framework knows how to initialize
objects from a model file. Simply by adding a model file to a project,
you make the model's database-to-object mapping available to the
Framework objects that need to reference it. All of the models
to an application are managed by an EOModelGroup object; see the
EOModelGroup class specification in the Enterprise Objects Framework
Reference for more information.
A data source is a subclass of the EODataSource abstract class that
presents an EODisplayGroup object with a standard interface to a store
of enterprise objects. From the perspective of the EODisplayGroup to
which a data source supplies enterprise objects, the actual mechanism
used for storing data is of no concern; everything below the data
is effectively a 'black box.' The interface layer interacts with all
sources in the same way. A data source takes care of communicating
the external data store to fetch, insert, update, and delete objects.
For most database applications, data sources are instances of
EODatabaseDataSource or EODetailDataSource (the data source classes
supplied with the Framework). EODatabaseDataSource, defined in
EOAccess, provides an interface to the Framework's access layer and
ultimately, to a relational database. However, the data source can be
object that is a subclass of the abstract class EODataSource. Thus,
user interface layer can be used independently from the access layer
other types of data sources, such as an array of objects constructed
application, or objects fetched from a flat-file database or a
[Continued in next message due to 4K limit]
With vertical mapping, a subclass can be added at any time without
modifying the Person table. Existing subclasses can also be modified
without affecting the other classes in the class hierarchy. The primary
virtue of this approach is its clean, normalized design.
Vertical mapping is the least efficient of all of the approaches. Every layer
of the class hierarchy requires a join to resolve the relationships. For
example, if you want to do a deep fetch from Person, three fetches are
performed: a fetch from Employee (with a join to Person), a fetch from
Customer (with a join to Person), and a fetch from Person to retrieve all
the Person attributes. (If Person is an abstract superclass for which no
objects are ever instantiated, the last fetch is not performed.)
In this approach, you have separate tables for Employee and Customer
that each contain columns for Person. The Employee and Customer
tables contain not only their own attributes, but all of the Person
attributes as well. If instances of Person exist that are not classified as
Employees or Customers, a third table would be required (where Person
is not an abstract class). In other words, with horizontal mapping every
concrete class has a self-contained database table that contains all of the
attributes necessary to instantiate objects of the class.
Similar to vertical mapping, a subclass can be added at any time without
modifying other tables. Existing subclasses can also be modified
without affecting the other classes in the class hierarchy.
This approach works well for deep class hierarchies, as long as the fetch
occurs against the leaves of the class hierarchy (Employee and Customer)
rather than against the root (Person). In the case of a deep fetch, it's more
efficient than vertical mapping (since no joins are performed). It's the
most efficient approach, if you only fetch instances of one leaf subclass
at a time.
Problems may occur when attributes need to be added to the Person
superclass. The number of tables that need to be altered is equal to the
number of subclasses'the more subclasses you have, the more effort
is required to maintain the superclass. However, if table maintenance
happens far less often than fetches, this might be a viable approach for
Single Table Mapping
In this approach, you put all of the data in one table that contains all
superclass and subclass attributes. Each row contains all of the columns
for the superclass as well as for all of the subclasses. The attributes that
don't apply for each object have NULL values. You fetch an Employee
or Customer by using a query that just returns objects of the specified
type (the table would probably include a type column to distinguish
records of one type from the other).
This approach is faster than the other two methods for deep fetches.
Unlike vertical or horizontal mapping, you can retrieve superclass objects
with a single fetch, without performing joins. Adding a subclass or
modifying the superclass requires changes to just one table.
Single table mapping can consume an inordinate amount of space since
every row includes columns for every one of the other entities' attributes.
This may depend on how your database stores NULLs. Some databases
condense NULL values, thereby reducing the storage space needed, but
some databases maintain the length of the actual data type of the column
regardless of the value stored. Most databases also have limitations
on how many columns a table can have (typically this is around
250 columns), which can make it impossible to use single table
mapping for a deep class hierarchy that has lots of instance variables.
Also, if you have a lot of data, this approach can actually be less efficient
than horizontal mapping since with single table mapping you have to
search the entire table to find the rows needed to instantiate objects
of a particular type. (Horizontal mapping is only more efficient if your
application just fetches one type of leaf object at a time (instances of a
Accessing Multiple Databases
Enterprise Objects Framework applications access multiple databases
almost transparently. Simply make different models for each database,
and then you can create relationships from an entity in one database to an
entity in another. In your application, you can fetch enterprise objects
from different databases into the same object graph without any extra
work. See the chapter Using EOModeler for more information.
However, there are a couple of pitfalls that can occur when you're
working with more than one database:
Enterprise Objects Framework doesn't implement a two-phase
EODatabaseDataSources with models for different databases can
erroneously rendezvous on the same EODatabaseContext.