[BioSQL-l] PersistentObjects
Hilmar Lapp
hlapp at gnf.org
Mon May 12 19:10:12 EDT 2003
The PersistentObjectI interface follows the Adapter pattern by way of
Composition (GoF p139). What we sloppily call adaptors isn't really
Adapters but rather facades for persistency operations (find, update,
delete, and variations thereof).
This dichotomy is represented by two interfaces: the interface(s) from
the bioperl object model that the object at hand complies with, e.g.,
Bio::SeqI, and the persistency interface Bio::DB::PersistentObjectI. A
persistent object obtained through the factory adapts one interface to
the other: you get an object that transparently still acts as the
bioperl object it was before (e.g., as a Bio::SeqI), but it now also is
persistence aware, i.e., you can delete or update it.
The implementation is through composition. I.e., a persistent object
internally delegates every persistence operation to an adaptor object
suitable for the particular bioperl interface.
So, to get back to your question, a persistent bioperl object provides
you with transparent access to persistence methods added on top of the
methods the bioperl object had itself already. Internally, those
persistence operations are handled by a database-aware adaptor object.
You could use the adaptor objects (implementing
Bio::DB::PersistenceAdaptorI) directly, but then you would have to carry
them around whenever you pass on the bioperl object to something that
might do something that involves a database operation. You would also
have to carry around the primary key. Apart from not having to worry
about or maintain the database adaptors and the primary keys, the
advantage of going through a persistent object is that then you can
transparently implement any amount of lazy-loading, at any time in the
future if need be, as a client code then does not rely on a certain
operation not involving a database operation. It is up to the persistent
object implementation what does involve a database operation and what
doesn't.
Also, inserting an object may involve storing foreign keys to objects it
references, or it may involve, for the purpose of user-convenience and
transparency, inserting objects that depend on it. In both cases, you
end up in a mess of code if the dependent or depending objects can't
easily serialize themselves if necessary and return their primary key to
you. If they are, however, persistent objects, you just ask them for
their primary key, and if there is none you ask the object to insert
itself. An example is inserting a Bio::SeqI object. If you say
$pseq = $db->create_persistent($seq);
$pseq->create();
what will happen behind the scenes is that
Bio::DB::BioSQL::SeqAdaptor->create($self) gets called, which will
determine the primary key of the associated Bio::Species and Namespace
objects, possibly by creating them if they don't exist yet. It will also
insert the associated Bio::SeqFeatureI and annotation objects, using the
primary key of the $pseq object as their foreign key.
If you used the database adaptor directly, you'd say
$adp = $db->get_object_adaptor($seq);
$adp->create($seq);
Now if you manipulated $seq subsequently, either by manipulating itself
or any of the objects it references, e.g., by adding SeqFeatureI
objects, how would you reflect this update in the database? If you want
to be generic, it is actually impossible to do this unless you still
know the primary key it received, because you may even have manipulated
those attributes that participate in the natural primary key, like
accession or version. If you don't want to be generic, it is just a mess
of code you need to write. Whereas, with using the persistent object all
you need to say is
$pseq->store();
and since it knows its primary key and all dependent objects know their
primary key the whole hierarchy of objects can be updated.
It may actually be instructive to look at the operations that take place
behind the scenes when you issue simple persistence operations like the
above. You can easily obtain a logging trail by calling
$db->verbose(1);
right after you obtain $db (the adaptor factory) from
Bio::DB::BioDB->new(...). You can also look at the output of a test
after setting the environment HARNESS_VERBOSE:
$ setenv HARNESS_VERBOSE 1
$ make test_swiss TEST_VERBOSE=1
Hope this helps.
-hilmar
> -----Original Message-----
> From: Juguang Xiao [mailto:juguang at tll.org.sg]
> Sent: Monday, May 12, 2003 2:43 AM
> To: biosql-l at open-bio.org
> Subject: [BioSQL-l] PersistentObjects
>
>
> Hi all,
>
> I read the code of bioperl-db, but still cannot catch why you use
> persistent objects to store its biological object, rather than use
> adaptor directly. Do you mind to explain?
>
> And is there any demo on seq feature or ontology?
>
> Thanks a lot.
>
> Juguang
>
> ------------ATGCCGAGCTTNNNNCT--------------
> Juguang Xiao
> Temasek Life Sciences Laboratory, National University of
> Singapore 1 Research Link, Singapore 117604 juguang at tll.org.sg
>
> _______________________________________________
> BioSQL-l mailing list
> BioSQL-l at open-bio.org http://open-bio.org/mailman/listinfo/biosql-l
>
More information about the BioSQL-l
mailing list