📄 tiofp documentation - what is an object persistence framework.htm
字号:
along with the vendor-specific implementations that will also be
developed.<BR><EM><BR>Yes. Currently we have Oracle via DOA, Paradox via BDE,
Interbase via IBObjects, and multi tier via HTTP and a custom ISAPI DLL. To
write another persistence flavor, clone the code from one of the above, modify
and recompile into a new package which gets loaded at
startup.</EM><BR></LI></OL>
<H2>How the tiOPF compares with Scott Ambler’s requirements</H2>
<P>The following 14 requirements where lifted from his paper on object
persistence frameworks: ‘The design of a robust persistence layer for relational
databases’ which can be found in full at <A
href="http://www.ambysoft.com/persistenceLayer.pdf">http://www.ambysoft.com/persistenceLayer.pdf</A></P>
<OL>
<LI><STRONG>Several types of persistence mechanism.</STRONG> A persistence
mechanism is any technology that can be used to permanently store objects for
later update, retrieval and/or deletion. Possible persistence mechanisms
include flat files, relational databases, object-relational databases, etc.
Scott’s paper concentrates on the relational aspect of persistence
layers.<BR><BR><EM>This requirement is partially met. The tiOPF is optimised
for object RDBMS mapping, and is currently being extended to support flat file
and XML persistence layers. This, however is not a trivial task because in the
process of optimising the framework for OO-RDBMS mapping, we have boxed our
selves into a design corner which is making it difficult to create a
persistence layer that maps to a not SQL database.</EM><BR>
<LI>Full encapsulation of the persistence mechanism(s). Ideally you should
only have to send the messages save, delete and retrieve to an object to save
it, delete it or retrieve it respectively. That’s it, the persistence layer
takes care of the rest. Furthermore, except for well-justified exceptions, you
shouldn’t have to write any special persistence code other than of the
persistence layer itself.<BR><BR><EM>This requirement is well met, although
you do not send a message like save or retrieve to the object, you pass the
object to the persistence manager and ask it to handle the saving.<BR><BR>For
example, you do not call: FMyObject.Save ; <BR>but rather gPerMgr.Save(
FMyObject ) ;</EM><BR>
<LI><STRONG>Multi-object actions.</STRONG> Because it is common to retrieve
several objects at once, perhaps for a report or as the result of a customised
search, a robust persistence layer must be able to support the retrieval of
many objects simultaneously. The same can be said of deleting objects from the
persistence mechanism that meet specific criteria.<BR><EM><BR>This requirement
is well met. You can make a call like gPerMgr.Read( FPeople ) where FPeople is
an empty list which will hold 0..n TPerson(s)<BR><BR>You can also make calls
like FPeople.Delete which will mark all the TPerson(s) in the list for
deletion. When gPerMgr.Save( FPeople ) is called, all the TPerson(s) marked
for deletion will be removed from the persistence store.</EM><BR>
<LI><STRONG>Transactions.</STRONG> Related to requirement #3 is the support
for transactions, a collection of actions on several objects. A transaction
could be made up of any combination of saving, retrieving, and/or deleting of
objects. Transactions may be flat, an ‘all-or-nothing’ approach where all the
actions must either succeed or be rolled back (cancelled), or they may be
nested, an approach where a transaction is made up of other transactions which
are committed and not rolled back if the last transaction fails. Transactions
also be short-lived, running in thousandths of a second, or ling-lived, taking
hours, days, or weeks, or even months to complete.<BR><BR><EM>This requirement
is partially met. Transactions are supported if the persistence mechanism
supports them. (ie a RDBMS). A single transaction will be supported per call
to the persistence layer. For example, all objects being saved in a call to
gPerMgr.Save(FPeople) will be saved in the same transaction. If one fails to
save, none will be saved. The abstract business object has a property
ObjectState which indicates if an object is clean (it does not need to be
saved) or dirty, (it must be created, updated or deleted) A single transaction
can exist between the objects and the database. The is no support for inter
object transactions, or object-GUI transactions.</EM><BR>
<LI><STRONG>Extensibility.</STRONG> You should be able to add new classes to
your object application and be able to change persistence mechanisms easily
(you can count on at least upgrading your persistence mechanism over time, if
not port to one from a different vendor). In other words your persistence
layer must be flexible enough to allow your application programmers and
persistence mechanism administrators to each do what they need to
do.<BR><BR><EM>Not really sure what Scott is getting at here. It is possible
to add new objects to the application (I can’t see when it would never be
possible).<BR><BR>The persistence connection mechanism is wrapped up in a
Delphi package which is loaded when the application initialises so changing
from one database access API is as easy as loading a different package
(BPL)<BR></EM>
<LI><STRONG>Object identifiers.</STRONG> An object identifier (Ambler, 1998c),
or OID for short, is an attribute, typically a number that uniquely identifies
an object. OIDs are the object-oriented equivalent of keys from relational
theory, columns that uniquely identify a row within a table.<BR><BR>Scott’s
high-low long integer based OIDs are implemented. There is no support for non
integer OIDs and this should probably be a requirement as it makes it
difficult to map to many legacy databases.<BR>
<LI><STRONG>Cursors.</STRONG> A persistence layer that supports the ability to
retrieve many objects with a single command should also support the ability to
retrieve more than just objects. The issue is one of efficiency: Do you really
want to allow users to retrieve every single person object stored in your
persistence mechanism, perhaps millions all at once? Of course not. An
interesting concept from the relational world is that of a cursor. A cursor is
a logical connection to the persistence mechanism from which you can retrieve
objects using a controlled approach, usually several at a time. This is often
more efficient than returning hundreds or even thousands of objects all at
once because the user may not need all of the objects immediately (perhaps
they are scrolling through a list).<BR><BR><EM>There is no support for
cursors.</EM><BR>
<LI><STRONG>Proxies.</STRONG> A complementary approach to cursors is that of a
‘proxy’. A proxy is an object that represents other objects but does not incur
the same overhead as the object that it represents. A proxy contains enough
information for both the computer and the user to identify it and no more. For
example, a proxy for a person object would contain its OID so that the
application can identify it and the first name, last name and middle initial
so that the user could recognise whom the proxy object represents. Proxies are
commonly used when the results of a query are to be displayed in a list, from
which the user will select only one or two. When users select the proxy object
from the list the real object is retrieved automatically form the persistence
mechanism, an object that is much later than the proxy. For example, the full
person object may include an address and a picture of the person. By using
proxies you don’t need to bring all of this information across the network for
every person in the list, only the information that the user actually
wants.<BR><BR><EM>The principle discussed here is implemented, but not by
using proxies. The abstract business object has a property, ObjectState. One
possible ObjectState is posPK, meaning persistent object state ‘Primary Key’
This means the OID and enough information for a human to navigate a list of
the objects has been loaded.</EM><BR>
<LI><STRONG>Records.</STRONG> The vast majority of reporting tools available
in the industry today expect to take collections of database records as input,
not collections of objects. If your organisation is using such a tool for
creating reports within an object-oriented application your persistence layer
should support the ability to simply return records as the result of retrieval
requests in order to avoid the overhead of converting the database records to
objects and then back to records.<BR><BR><EM>There is no support for records,
although there is a record like family of classes. The easy alternative to
this would be to hook into a TClientDataSet, however this was not done to
avoid building a dependency on the Enterprise version of Delphi.</EM><BR>
<LI><STRONG>Multiple architectures.</STRONG> As organisations move from
centralised mainframe architectures to 2-tier client/server architectures to
n-tier architectures to distributed objects your persistence layer should be
able to support these various approaches. The point to be made is that you
must assume that at some point your persistence layer will need to exist in a
range of potentially complex environments.<BR><BR><EM>This requirement has
been moderately well met. There is a remote persistence layer that will pass
all calls through the tiDBProxyServer and on to a database. The
tiDBProxyServer is a standalone Windows Service (build using TIndyHTTPServer).
The service may be recompiled as an ISAPI DLL to run under IIS.</EM><BR>
<LI><STRONG>Various database versions and/or vendors</STRONG>. Upgrades
happen, as do ports to other persistence mechanisms. A persistence layer
should support the ability to easily change persistence mechanisms without
affecting the applications that access them, therefore a wide variety of
database versions and vendors, should be supported by the persistence
layer.<BR><BR><EM>This requirement is well met. To connect to a different
database or using a different connection API, just load an alternative Delphi
package at runtime.<BR></EM>
<LI><STRONG>Multiple connections</STRONG>. Most organisations have more than
one persistence mechanism, often from different vendors, that need to be
accessed by a single object application. The implication is that a persistence
layer should be able to support multiple, simultaneous connections to each
applications persistence mechanism. Even something as simple as copying an
object from one persistence mechanism to another, perhaps from a centralised
relational database to a local relational database, requires at least two
simultaneous connections, one to each database.<BR><BR><EM>Multiple
connections to a single database (via database connection pooling), or
multiple connections to multiple databases of the same access are possible.
Work has been commenced to allow multiple connections to different database
types and it will not be too difficult to meet this requirement.</EM><BR>
<LI><STRONG>Native and non-native drivers.</STRONG> There are several
different strategies for accessing a relational database, and a good
persistence layer will support the most common ones. Connection strategies
include using Open Database Connectivity (ODBC), Active Data Objects (ADO),
and native drivers supplied by the database vendor and/or third party
vendor.<BR><BR><EM>This requirement is well met by swapping runtime
packages.</EM><BR>
<LI><STRONG>Structured query language (SQL) queries</STRONG>. Writing SQSL
queries in your object-oriented code is a fragrant violation of encapsulation
– you’ve coupled your application directly to the database schema. However,
for performance reasons you sometimes need to do so. Hard-coded SQSL in your
application should be the exceptions, not the norm, an exception that should
be well-justified before being allowed to occur. The persistence layer will
need to support the ability do directly submit SQL code to a relational
database.<BR><BR><EM>Several ways of submitting SQL to the database are
possible.<BR><BR>The default is for the SQL to be maintained with a tool
called the tiSQLManager that stores the SQL in the database. This has many
advantages but it does mean the three tiSQLManager tables must exist in the
database.<BR><BR>SQL can be generated on the fly (this requires work before it
could be regarded as production quality)<BR><BR>SQL can be hard-coded into the
application.</EM> </LI></OL>
<P>The next section</P>
<P>The next section describes the Visitor framework and can be read <A
href="http://www.techinsite.com.au/tiOPF/Doc/2_TheVisitorFramework.htm">here</A>.
</P><!-- InstanceEndEditable -->
<DIV id=Footer>(c) TechInsite Pty Ltd, Melbourne, Australia.
www.techinsite.com.au</DIV></DIV><!-- InstanceEnd --></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -