[Modeling-cvs] ProjectModeling/Modeling/doc/UserGuide CodeRequirements.tex,NONE,1.1 CustomObject.tex
Status: Abandoned
Brought to you by:
sbigaret
Update of /cvsroot/modeling/ProjectModeling/Modeling/doc/UserGuide
In directory sc8-pr-cvs1:/tmp/cvs-serv27433/Modeling/doc/UserGuide
Modified Files:
CustomObject.tex ManipulatingGraphOfObjects.tex
NestedEditingContext.tex
Added Files:
CodeRequirements.tex
Log Message:
documentation: moved the section on KeyValueCoding and
RelationshipManipulation to an 'advanced techniques' part. Added raw
material about fetching and inheritance. Updated to reflect the API
change.
--- NEW FILE: CodeRequirements.tex ---
\chapter{Functionalities for Object Management\label{code-requirements}}
All python objects must inherit from the framework class
\class{CustomObject}, to be thus connected to the framework's core.
The \class{CustomObject} class defines all the necessary logic to make it
possible to ensure the objects' persistency within the RDBMS, as well as
numerous functionalities to help you with your own business logic. For those
purposes, it works with a model, from which the classes are generally
generated.
This chapter presents some important issues that you should not forget when
coding and customizing your classes and logic--particularly important are the
methods \method{willRead} and \method{willChange}. We will also look at other
functionalities you can take advantage of, among which: validation of the
referential constraints and custom validation logic.
Note that, you may start working directly with the generated classes for your
model--adding, modifying, and getting data (as explained in chapter
\ref{editing-context})--and letting the framework do the above-mentioned tasks
transparently. The information here is provided to allow you to better
understand how the framework performs these tasks, and to thus make it easier
to add to, or modify, the framework's default behaviour to better suit your
application needs, e.g. to add custom validation logic.
{\bf Note}: Only a small sampling of the methods and functionalities of the
\class{CustomObject} class, and other supporting classes, are mentioned here.
For a complete picture you will need to look at the source doc strings, for
\class{CustomObject} itself, as well as the doc strings for the interfaces it
implements, namely \class{RelationshipManipulation},
\class{KeyValueCoding} (these two interfaces are exposed in details in
chapter~\ref{custom-object}) and \class{DatabaseObject}.
\section{The python package generated from an XML model \label{basics-CustomObject}}
We take the model \code{AuthorBooks} as an example--you'll find it at:\\
\file{Modeling/tests/testPackages/AuthorBooks/model_AuthorBooks.xml}.
In this model, we have two entities, \class{Writer} and \class{Book}:
\begin{verbatim}
+--------+ +------+
| Writer |<-author----------books->| Book |
|--------| |------|
| | | |
| |<-pygmalion--+ | |
+--------+ | +------+
| |
+-----------------+
\end{verbatim}
When you generate the python code for that model, you get a
\module{AuthorBooks} package.
\begin{itemize}
\item \module{__init__.py} takes care to load the model within the default
\class{ModelSet},
\item the model xml file is dropped within the package,
\item you get two modules, \module{Writer} and \module{Book}, containing,
respectively the classes \class{Book} and \class{Writer}.
\end{itemize}
Let's have a look at the \class{Book} class -- I won't copy it here, go to
\file{Modeling/tests/testPackages/AuthorBooks/Book.py} and keep an eye on
it (or generate your own copy using the ZModelizationTool or the provided
scripts).
Let's take a look at the code. After the initial imports, we get:
\begin{enumerate}
\item class declaration:
\begin{verbatim}
class Book (CustomObject):
\end{verbatim}
i.e.: every object should derive from \class{CustomObject}, which
defines the appropriate methods.
\item Initializer: defines some default values for your attributes.
{\bf Note}: It {\bf must} be possible to call the \method{__init__}
with no arguments at all. If you want to add arguments to
\method{__init__}, each one should have default values. The reason for this is
that the framework relies on a call to \code{__init__()}, without any
arguments, when it needs to create an instance before populating it with data
fetched from the database.
\item \code{def entityName(self)}: this is the way the framework currently
binds an object to its entity. This should be changed (see TODO)
\item Then you get setters and getters for the attributes, whose exact form
depends on their nature (attributes, to-one or to-many relationships).
There is also some validation code ready to be used. See
\ref{customobject-validation}, ``Validation'' for details.
In getters and setters, notice the methods \method{willRead()} and
\method{willChange()}. These methods are defined by \class{CustomObject}.
\begin{itemize}
\item \method{willRead} informs the object that we need the values stored in
the database. This is because objects can be ``{\em faults}'' (ZODB
speaking, they are ghosts). This method's job is to initialize the
object.
\item \method{willChange} informs the object that it is about to change. This
is part of the \class{Observing} interface, and its purpose is to notify
the \class{EditingContext} that an object is about to change; the
\class{EditingContext} needs this to keep track of changes in its graph
of objects. ZODB speaking, this is what the mix-in class
\class{Persistent} does transparently for immutable attributes (see
also: TODO).
Of course, \method{willChange} invokes \method{willRead} when
appropriate.
\begin{notice}[warning]
It is your responsability to call \method{willRead} and
\method{willChange} when you are about to, respectively, access or
change a class attribute corresponding to a Model's Attribute or
Relationship; if you do not, the \class{EditingContext}, which is
responsible for examining the changes and making them persistent, is
likely to do only part of its job, possibly resulting in objects being
partially saved, or not at all.
\end{notice}
\end{itemize}
\end{enumerate}
That's it. You can then start coding your own business logic. Objects are
always inserted, deleted or updated in a database via an instance of the
\class{EditingContext} class (see chapter \ref{editing-context}, ``Working
with your objects: insert, changes, deletion'').
\section{Automatic validation of referential and business-logic constraints
\label {customobject-validation}}
A major part of the checks made at runtime are validation operations --for
example, you want to verify that a zipCode has a valid format, that the
age of a person is a positive integer, etc.
The framework defines an interface, \class{Validation}, which allows you
and the framework as well to trigger these validations when needed, in a
defined scheme. You automatically get these functionalities when your
class inherits from \class{Modeling.CustomObject} and corresponds to an
entity defined in a model.
There is, roughly, two kinds of validation checks. The first one consists
in checking individual properties of an object (such as: check that a
value for a given key is of the proper type, that its width is ok if it is
a 'string', etc.); the second one considers objects as a whole: its
checks are like post-conditions, or consistency checking. We will see in
the following how both can be adjusted and triggered.
\subsection{Integrity constraints derived from the underlying model\label{customobject-validation-integrity}}
When you define a model, you also define a number of constraints that has
to be checked. For example, lower- and upper- bounds of a relationship's
multiplicity, say (min=1, max=3), specify that an object cannot have less
than one object (of a certain type!) in relation with itself, and no more
than three as well. You can also mark an attribute as 'required' to avoid
it being \constant{None}.
The framework naturally verifies these constraints: the checking occurs
automatically when an EditingContext is about to save changes (we will see
hereafter how this can be manually triggered).
The constraints that are enforced are the following:
\begin{itemize}
\item Attributes:
\begin{itemize}
\item type of the stored value,
\item if it is marked as 'required', it shouldn't be \constant{None}
\end{itemize}
\item Relationships:
\begin{itemize}
\item the type of the objects in relation with oneself,
\item the number of objects in relation {\em vs.} the relationship's
multiplicity.
\end{itemize}
\end{itemize}
\subsection{Checking constraints: key by key\label{customobject-validation-by-key}}
To verify a given value for a specific attribute, say on \var{lastName}
for a \class{Writer} object, you use the method
\method{validateValueForKey}:
\begin{verbatim}
aWriter.validateValueForKey('Cleese', 'lastName')
\end{verbatim}
This check that the value \code{'Cleese'} is a valid value for
\var{Writer.lastName}. Note that this value is directly given as a
parameter and is not stored, nor searched, within the object: the
validation can thus be done without actually assigning the value to an
attribute (but the ``global'' checks we'll see hereafter do not work that
way).
\subsubsection{Return code\label{customobject-validation-return-code}}
When the value is valid, \method{validateValueForKey} simply
returns. But if it encounters an error, it raises the exception
\class{Validation.ValidationException}. This exception holds a
dictionary gathering the reasons of failure; this dictionary has the
following characteristics:
\begin{itemize}
\item its keys are names of attributes for which the validation failed,
\item the corresponding values indicates the reason(s) for the failure.
\end{itemize}
For example, suppose we called \code{aWriter.validateValueForKey('',
'lastName')} and that attribute \var{lastName} is marked as 'required',
the raised exception's dictionary is then::
\begin{verbatim}
{'lastName': ['Key is required but value is void',],
}
\end{verbatim}
If \method{validateValueForKey} raises an exception, the dictionary will
only contain one key: the one that was supplied as the parameter 'key'.
Its corresponding value is a list of all observed errors; here, it
corresponds to the constant \constant{Validation.REQUIRED} defined in
the Validation interface. You will find there the complete list of
possible error codes.
\subsubsection{How to define your own validation logic\label{customobject-validation-custom-logic}}
Now suppose that you want to enforce that the value stored in the
\var{lastName} attribute does not begin with a \code{'J'}. This sort of
constraint is not expressed within the model, so you have
to write some code for that, and you want that to be checked
transparently, along with other constraints.
The \method{validateValueForKey} is ready for such a situation: it
expects you to write a method named \method{validateLastName} (note the
capitalized letter in \method{validate{\bf L}astName}). If
it exists, then it gets automatically called. This is how you would
write it:
\begin{verbatim}
from Modeling import Validation
def validateLastName(self, aValue):
"Checks that the provided value does not begin with a 'J'"
if aValue.find('J')==0:
raise Validation.Exception
return
\end{verbatim}
Let's call \code{aWriter.validateValueForKey("Jleese", "lastName")} one
more time, catch the exception, and checks its error dictionary:
\begin{verbatim}
{ 'lastName': ['Custom validation of key failed'],
}
\end{verbatim}
Our own validation method has been taken into account, as expected, and
the value \constant{Validation.CUSTOM_KEY_VALIDATION}, part of the
errors for key \var{lastName}, signals it.
\subsection{\class{Validation.ValidationException}: the list of error-codes \label{customobject-validation-list-errors}}
The values that can be found in the list of reasons of failures for a
given key are the following (extracted from the \class{Validation}
interface):
\begin{verbatim}
REQUIRED="Key is required but value is void"
TYPE_MISMATCH="Wrong type"
CUSTOM_KEY_VALIDATION="Custom validation of key failed"
LOWER_BOUND="Lower bound of key's multiplicity constraint not fulfilled"
UPPER_BOUND="Upper bound of key's multiplicity constraint not fulfilled"
DELETE_DENY_KEY="Key has rule 'DELETE_DENY' but object still holds object(s)"
CUSTOM_OBJECT_VALIDATION="Custom validation of object as a whole failed"
OBJECT_WIDE="Validation of object as a whole failed"
OBJECT_WIDE_KEY='OBJECT_WIDE_VALIDATION'
\end{verbatim}
The last three items occurs when an object is validated as a whole, not
when its individual properties are checked; all other values can be
returned by \method{validateValueForKey}.
\subsection{Validating an object ``as a whole''\label{customobject-validation-invariants}}
We know how specific properties can be checked, but we still need a way to
validate the consistence of the whole object, so that e.g. invariants of
an object are ensured before its data is stored in the database. The
framework defines the following methods for that purpose:
\begin{itemize}
\item \method{validateForInsert()}
\item \method{validateForUpdate()}
\item \method{validateForSave()}
\item \method{validateForDelete()}
\end{itemize}
The two first methods simply calls the third one. The fourth one verifies
a particular set of constraints we'll see in a moment.
\subsubsection{\method{validateForSave()}\label{validate-for-save}}
This method iterates on every key (attribute {\bf and} relation) and
calls \method{validateValueForKey} for each of them, using the stored
value as the parameter 'value'.
\begin{notice}
if you defined your own validation logic for some keys, they are called as
well, as expected and seen above.
\end{notice}
You can also define your own global validation method, like:
\begin{verbatim}
from Modeling import Validation
def validateForSave(self):
"Validate "
error=Validation.Exception()
try:
CustomObject.validateForSave(self)
except Validation.Exception, error:
error.aggregateException(error)
# Your custom bizness logic goes here
if self.getFirstName()=='John': # No John, except the One
if self.getLastName()!='Cleese':
error.aggregateError(Validation.CUSTOM_OBJECT_VALIDATION,
Validation.OBJECT_WIDE_KEY)
error.finalize() # raises, if appropriate
\end{verbatim}
Now suppose that our object \code{aWriter} stores \code{Jleese} for
\var{lastName} and \code{John} for \var{firstName}. The dictionary of
errors stored in the raised exception, after \method{validateForSave} is
called, will be:
\begin{verbatim}
{ 'OBJECT_WIDE_VALIDATION':
['Validation of object as a whole failed',
'Custom validation of object as a whole failed'],
'lastName':
['Custom validation of key failed'],
}
\end{verbatim}
The value \constant{Validation.OBJECT_WIDE_KEY} is used to report global
validation errors. You will find it {\bf as soon as an error has been
detected while validating}. Here you find an other value for that key,
\constant{Validation.CUSTOM_OBJECT_VALIDATION}, indicating that our own
code did not validate the values as well. Note that the validation for
key \var{lastName} has failed as well and is also reported.
\begin{notice}[warning]
{\bf IMPORTANT NOTE} -- contrary to what happens with methods
\method{validate<AttributeName>}, the method \method{validateForSave()}
we defined here overrides the definition inherited from
\class{CustomObject}. Hence, it is very important not to forget calling
the superclass' implementation, as described in the code above.
\end{notice}
\subsubsection{\method{validateForDelete()}\label{validate-for-delete}}
TBD.
\subsection{Misc.\label{customobject-misc}}
A \class{Validation.ValidationException} object defines \method{__str__},
so for the previous example, \code{str(error)} says::
\begin{verbatim}
Validation for key OBJECT_WIDE_VALIDATION failed:
- Validation of object as a whole failed
- Custom validation of object as a whole failed
Validation for key name failed:
- Custom validation of key failed
\end{verbatim}
Index: CustomObject.tex
===================================================================
RCS file: /cvsroot/modeling/ProjectModeling/Modeling/doc/UserGuide/CustomObject.tex,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** CustomObject.tex 19 May 2003 16:05:16 -0000 1.4
--- CustomObject.tex 4 Jul 2003 17:06:52 -0000 1.5
***************
*** 1,141 ****
! \chapter{Functionalities for Object Management\label{custom-object}}
!
! All python objects must inherit from the framework class
! \class{CustomObject}, to be thus connected to the framework's core.
! The \class{CustomObject} class defines all the necessary logic to make it
! possible to ensure the objects' persistency within the RDBMS, as well as
! numerous functionalities to help you with your own business logic. For those
! purposes, it works with a model, from which the classes are generally
! generated.
!
! This chapter presents some important issues that you should not forget when
! coding and customizing your classes and logic--particularly important are the
! methods \method{willRead} and \method{willChange}. We will also look at other
! functionalities you can take advantage of, among which: validation of the
! referential constraints, custom validation logic, and dynamic manipulation of
! an object's properties and relationships.
!
! Note that, you may start working directly with the generated classes for your
! model--adding, modifying, and getting data (as explained in chapter
! \ref{editing-context})--and letting the framework do the above-mentioned tasks
! transparently. The information here is provided to allow you to better
! understand how the framework performs these tasks, and to thus make it easier
! to add to, or modify, the framework's default behaviour to better suit your
! application needs, e.g. to add custom validation logic.
!
! {\bf Note}: Only a small sampling of the methods and functionalities of the
! \class{CustomObject} class, and other supporting classes, are mentoined here.
! For a complete picture you will need to look at the source doc strings, for
! \class{CustomObject} itself, as well as the doc strings for the interfaces it
! implements, namely \class{RelationshipManipulation} and
! \class{DatabaseObject}.
!
!
! \section{The python package generated from an XML model \label{basics-CustomObject}}
!
! We take the model \code{AuthorBooks} as an example--you'll find it at:
! \file{Modeling/tests/testPackages/AuthorBooks/model_AuthorBooks.xml}.
!
!
! In this model, we have two entities, \class{Writer} and \class{Book}:
\begin{verbatim}
! +--------+ +------+
! | Writer |<-author----------books->| Book |
! |--------| |------|
! | | | |
! | |<-pygmalion--+ | |
! +--------+ | +------+
! | |
! +-----------------+
\end{verbatim}
! When you generate the python code for that model, you get a
! \module{AuthorBooks} package.
!
! \begin{itemize}
! \item \module{__init__.py} takes care to load the model within the default
! \class{ModelSet},
!
! \item the model xml file is dropped within the package,
!
! \item you get two modules, \module{Writer} and \module{Book}, containing,
! respectively the classes \class{Book} and \class{Writer}.
!
! \end{itemize}
!
! Let's have a look at the \class{Book} class -- I won't copy it here, go to
! \file{Modeling/tests/testPackages/AuthorBooks/Book.py} and keep an eye on
! it (or generate your own copy using the ZModelizationTool or the provided
! scripts).
!
!
! Let's take a look at the code. After the initial imports, we get:
!
! \begin{enumerate}
! \item class declaration:
! \begin{verbatim}
! class Book (CustomObject):
! \end{verbatim}
! i.e.: every object should derive from \class{CustomObject}, which
! defines the appropriate methods.
!
! \item Initializer: defines some default values for your attributes.
! {\bf Note}: It {\bf must} be possible to call the \method{__init__}
! with no arguments at all. If you want to add arguments to
! \method{__init__}, each one should have default values. The reason for this is
! that the framework relies on a call to \code{__init__()}, without any
! arguments, when it needs to create an instance before populating it with data
! fetched from the database.
!
! \item \code{def entityName(self)}: this is the way the framework currently
! binds an object to its entity. This should be changed (see TODO)
! \item Then you get setters and getters for the attributes, whose exact form
! depends on their nature (attributes, to-one or to-many relationships).
! There is also some validation code ready to be used. See
! \ref{customobject-validation}, ``Validation'' for details.
! In getters and setters, notice the methods \method{willRead()} and
! \method{willChange()}. These methods are defined by \class{CustomObject}.
! \begin{itemize}
! \item \method{willRead} informs the object that we need the values stored in
! the database. This is because objects can be ``{\em faults}'' (ZODB
! speaking, they are ghosts). This method's job is to initialize the
! object.
! \item \method{willChange} informs the object that it is about to change. this
! is part of the \class{Observing} interface, and its purpose is to notify
! the \class{EditingContext} that an object is about to change; the
! \class{EditingContext} needs this to keep track of changes in its graph
! of objects. ZODB speaking, this is what the mix-in class
! \class{Persistent} does transparently for immutable attributes (see
! also: TODO).
!
! Of course, \method{willChange} invokes \method{willRead} when
! appropriate.
! \begin{notice}[warning]
! It is your responsability to call \method{willRead} and
! \method{willChange} when you are about to, respectively, access or
! change a class attribute corresponding to a Model's Attribute or
! Relationship; if you do not, the \class{EditingContext}, which is
! responsible for examining the changes and making them persistent, is
! likely to do only part of its job, possibly resulting in objects being
! partially saved, or not at all.
! \end{notice}
! \end{itemize}
! \end{enumerate}
! That's it. You can then start coding your own business logic. Objects are
! always inserted, deleted or updated in a database via an instance of the
! \class{EditingContext} class (see chapter \ref{editing-context}, ``Working
! with your objects: insert, changes, deletion'').
\section{Manipulating objects and their relationships\label{customobject-relationshipmanipulation}}
! With the methods defined by this interface, you can assign an object
\class{Book} to another object \class{Author}, and conversely, without
even knowing if the relationship has some inverse relationship, or even if
--- 1,76 ----
! \chapter{Accessing a model and its properties\label{accessing-model-properties}}
+ Every model required at runtime is loaded into a single \class{ModelSet}, the
+ so-called ``default model set''. It is accessed this way:
\begin{verbatim}
! >>> from Modeling.ModelSet import defaultModelSet
! >>> ms=defaultModelSet()
\end{verbatim}
! Suppose we already imported the two test packages \module{AuthorBooks} and
! \module{StoreEmployees}, then we have:
! \begin{verbatim}
! >>> ms.modelsNames()
! ['AuthorBooks', 'StoreEmployees']
! \end{verbatim}
! The two corresponding models have been correctly imported, as expected.
! Accessing a model in particular, or one of its entities is straightforward:
! \begin{verbatim}
! >>> model_AuthorBooks=ms.modelNamed('AuthorBooks')
! >>> model_AuthorBooks.entitiesNames()
! ['Writer', 'Book']
! >>> model_AuthorBooks.entities()
! (<Entity instance at 8396b50>, <Entity instance at 8337cd0>)
! >>> entity_Book=model_AuthorBooks.entityNamed('Book')
! \end{verbatim}
! Note: you do not need to access a model to get one of its entities; since
! entities share a common namespace inside a \module{ModelSet}, this can be
! asked to the model set as well:
! \begin{verbatim}
! >>> ms.entitiesNames()
! ('Writer', 'Book', 'Store', 'Employee', 'Address', 'SalesClerk',
! 'Executive', 'Mark')
! >>> ms.entityNamed('Book')
! <Entity instance at 8337cd0>
! \end{verbatim}
! Last, given an entity, you can access its attributes and relationships quite
! the same way, for example:
! \begin{verbatim}
! >>> # All attributes' names
! ... entity_Book.attributesNames()
! ('title', 'id', 'price', 'FK_Writer_Id')
! >>> # All relationships' names
! ... entity_Book.relationshipsNames()
! ('author',)
! >>> # Class properties only
! ... entity_Book.classProperties()
! (<Attribute instance at 839bc38>, <Attribute instance at 83c5720>,
! <Attribute instance at 83eaca8>, <SimpleRelationship instance at 840b280>)
! >>> # and their names
! ... entity_Book.classPropertiesNames()
! ['title', 'id', 'price', 'author']
! >>> # dealing with an attribute
! ... book_title=entity_Book.attributeNamed('title')
! >>> book_title.type(), book_title.externalType(), book_title.width()
! ('string', 'VARCHAR', 40)
! \end{verbatim}
! Each of the classes \class{Model}, \class{Entity}, \class{Attribute} and
! \class{Relationship} have more functionalities then that. We invite you to
! look at their respective API for further details.
! \chapter{Generic manipulation of objects\label{custom-object}}
+ In this chapter, we'll see how each object's properties can be dynamically
+ handled.
\section{Manipulating objects and their relationships\label{customobject-relationshipmanipulation}}
! With the methods defined by the interface \class{RelationshipManipulation}
! (implemented by \class{CustomObject}), you can assign an object
\class{Book} to another object \class{Author}, and conversely, without
even knowing if the relationship has some inverse relationship, or even if
***************
*** 154,159 ****
the graph of object remains consistent.
! Of course, you can always do anything by hand, and the first statement is
! strictly equivalent (even if a bit slower) to:
\begin{verbatim}
_author=aBook.getAuthor()
--- 89,93 ----
the graph of object remains consistent.
! Compare this with that you normally do by hand, the explicit way:
\begin{verbatim}
_author=aBook.getAuthor()
***************
*** 164,171 ****
\end{verbatim}
! However, this can come in handy for rapid prototyping, or to make things
! smoother when you are beginning the dev. and that the model can rapidly
! change, or for designing generic algorithms where the manipulated objects
! and relationships are not known at runtime.
Last note: the inverse method is the following one:
--- 98,109 ----
\end{verbatim}
! \method{addObjectToBothSidesOfRelationshipWithKey} does exactly the same
! thing, taking care of all the details for you (even it's a bit slower than
! the explicit statements because it has to examine the model).
!
! This can come in handy for rapid prototyping, or to make things smoother
! when you are beginning the dev. and that the model can rapidly change, or
! for designing generic algorithms where the manipulated objects and
! relationships are not known at runtime.
Last note: the inverse method is the following one:
***************
*** 181,186 ****
(quick notes, needs to be further documented)
! The \class{KeyValueCoding} interface defines methods for accessing and
! setting values to keys. In fact, the \class{RelationshipManipulation}
interface is, somehow, the equivalent of the \class{KeyValueCoding} for
relationships.
--- 119,125 ----
(quick notes, needs to be further documented)
! The \class{KeyValueCoding} interface is also implemented by
! \class{CustomObject}; it defines methods for accessing and setting
! attributes' values to keys. In fact, the \class{RelationshipManipulation}
interface is, somehow, the equivalent of the \class{KeyValueCoding} for
relationships.
***************
*** 224,227 ****
--- 163,188 ----
\end{enumerate}
+ \subsection{The whole API\label{kvc-whole-api}}
+
+ \begin{itemize}
+ \item{\method{valueForKey()}} gets a value for a given attribute's name,
+ \item{\method{takeValueForKey()}} sets a value for a given attribute's name,
+ \item{\method{valueForKeyPath()}} is working the same way than
+ \method{valueForKey}, except that the key can be here expressed by dotted
+ notation to automatically access an other related object's property (such
+ as: \code{"author.lastName"} for a \class{Book} object --see examples,
+ below)
+ \item{\method{takeValueForKeyPath()}} is like \method{takeValueForKey} with
+ dotted notations
+ \end{itemize}
+
+ Additionally, two more methods are available:
+ \begin{itemize}
+ \item{\method{valuesForKeys()}}: returns the list of values taken by the
+ supplied attributes
+ \item{\method{takeValuesFromDictionary()}}: sets each key/attribute with its
+ corresponding value
+ \end{itemize}
+
\subsection{Examples\label{kvc-examples}}
***************
*** 240,493 ****
\item \code{aBook.takeValueForKeyPath("Hugo", "author.lastName")} is
equivalent to \code{aBook.getAuthor().setLastName("Hugo")}
- \end{itemize}
-
-
- Of course, the objects' properties may always still be accessed
- using the getters and setters of your python objects,
-
- \section{Automatic validation of referential and business-logic constraints
- \label {customobject-validation}}
-
- A major part of the checks made at runtime are validation operations --for
- example, you want to verify that a zipCode has a valid format, that the
- age of a person is a positive integer, etc.
-
- The framework defines an interface, \class{Validation}, which allows you
- and the framework as well to trigger these validations when needed, in a
- defined scheme. You automatically get these functionalities when your
- class inherits from \class{Modeling.CustomObject} and corresponds to an
- entity defined in a model.
-
- There is, roughly, two kinds of validation checks. The first one consists
- in checking individual properties of an object (such as: check that a
- value for a given key is of the proper type, that its width is ok if it is
- a 'string', etc.); the second one considers objects as a whole: its
- checks are like post-conditions, or consistency checking. We will see in
- the following how both can be adjusted and triggered.
-
-
- \subsection{Integrity constraints derived from the underlying model\label{customobject-validation-integrity}}
-
- When you define a model, you also define a number of constraints that has
- to be checked. For example, lower- and upper- bounds of a relationship's
- multiplicity, say (min=1, max=3), specify that an object cannot have less
- than one object (of a certain type!) in relation with itself, and no more
- than three as well. You can also mark an attribute as 'required' to avoid
- it being \constant{None}.
-
- The framework naturally verifies these constraints: the checking occurs
- automatically when an EditingContext is about to save changes (we will see
- hereafter how this can be manually triggered).
-
- The constraints that are enforced are the following:
- \begin{itemize}
- \item Attributes:
- \begin{itemize}
- \item type of the stored value,
- \item if it is marked as 'required', it shouldn't be \constant{None}
- \end{itemize}
- \item Relationships:
- \begin{itemize}
- \item the type of the objects in relation with oneself,
- \item the number of objects in relation {\em vs.} the relationship's
- multiplicity.
- \end{itemize}
- \end{itemize}
-
- \subsection{Checking constraints: key by key\label{customobject-validation-by-key}}
-
- To verify a given value for a specific attribute, say on \var{lastName}
- for a \class{Writer} object, you use the method
- \method{validateValueForKey}:
-
- \begin{verbatim}
- aWriter.validateValueForKey('Cleese', 'lastName')
- \end{verbatim}
-
- This check that the value \code{'Cleese'} is a valid value for
- \var{Writer.lastName}. Note that this value is directly given as a
- parameter and is not stored, nor searched, within the object: the
- validation can thus be done without actually assigning the value to an
- attribute (but the ``global'' checks we'll see hereafter do not work that
- way).
-
- \subsubsection{Return code\label{customobject-validation-return-code}}
-
- When the value is valid, \method{validateValueForKey} simply
- returns. But if it encounters an error, it raises the exception
- \class{Validation.ValidationException}. This exception holds a
- dictionary gathering the reasons of failure; this dictionary has the
- following characteristics:
-
- \begin{itemize}
- \item its keys are names of attributes for which the validation failed,
- \item the corresponding values indicates the reason(s) for the failure.
- \end{itemize}
-
- For example, suppose we called \code{aWriter.validateValueForKey('',
- 'lastName')} and that attribute \var{lastName} is marked as 'required',
- the raised exception's dictionary is then::
-
- \begin{verbatim}
- {'lastName': ['Key is required but value is void',],
- }
- \end{verbatim}
-
- If \method{validateValueForKey} raises an exception, the dictionary will
- only contain one key: the one that was supplied as the parameter 'key'.
- Its corresponding value is a list of all observed errors; here, it
- corresponds to the constant \constant{Validation.REQUIRED} defined in
- the Validation interface. You will find there the complete list of
- possible error codes.
-
-
- \subsubsection{How to define your own validation logic\label{customobject-validation-custom-logic}}
! Now suppose that you want to enforce that the value stored in the
! \var{lastName} attribute does not begin with a \code{'J'}. This sort of
! constraint is not expressed within the model, so you have
! to write some code for that, and you want that to be checked
! transparently, along with other constraints.
!
! The \method{validateValueForKey} is ready for such a situation: it
! expects you to write a method named \method{validateLastName} (note the
! capitalized letter in \method{validate{\bf L}astName}). If
! it exists, then it gets automatically called. This is how you would
! write it:
!
! \begin{verbatim}
! from Modeling import Validation
!
! def validateLastName(self, aValue):
! "Checks that the provided value does not begin with a 'J'"
! if aValue.find('J')==0:
! raise Validation.Exception
! return
! \end{verbatim}
!
! Let's call \code{aWriter.validateValueForKey("Jleese", "lastName")} one
! more time, catch the exception, and checks its error dictionary:
! \begin{verbatim}
! { 'lastName': ['Custom validation of key failed'],
! }
! \end{verbatim}
!
! Our own validation method has been taken into account, as expected, and
! the value \constant{Validation.CUSTOM_KEY_VALIDATION}, part of the
! errors for key \var{lastName}, signals it.
!
! \subsection{\class{Validation.ValidationException}: the list of error-codes \label{customobject-validation-list-errors}}
!
! The values that can be found in the list of reasons of failures for a
! given key are the following (extracted from the \class{Validation}
! interface):
!
! \begin{verbatim}
! REQUIRED="Key is required but value is void"
! TYPE_MISMATCH="Wrong type"
! CUSTOM_KEY_VALIDATION="Custom validation of key failed"
! LOWER_BOUND="Lower bound of key's multiplicity constraint not fulfilled"
! UPPER_BOUND="Upper bound of key's multiplicity constraint not fulfilled"
! DELETE_DENY_KEY="Key has rule 'DELETE_DENY' but object still holds object(s)"
! CUSTOM_OBJECT_VALIDATION="Custom validation of object as a whole failed"
! OBJECT_WIDE="Validation of object as a whole failed"
! OBJECT_WIDE_KEY='OBJECT_WIDE_VALIDATION'
! \end{verbatim}
!
! The last three items occurs when an object is validated as a whole, not
! when its individual properties are checked; all other values can be
! returned by \method{validateValueForKey}.
!
!
! \subsection{Validating an object ``as a whole''\label{customobject-validation-invariants}}
!
! We know how specific properties can be checked, but we still need a way to
! validate the consistence of the whole object, so that e.g. invariants of
! an object are ensured before its data is stored in the database. The
! framework defines the following methods for that purpose:
- \begin{itemize}
- \item \method{validateForInsert()}
- \item \method{validateForUpdate()}
- \item \method{validateForSave()}
- \item \method{validateForDelete()}
\end{itemize}
! The two first methods simply calls the third one. The fourth one verifies
! a particular set of constraints we'll see in a moment.
!
! \subsubsection{\method{validateForSave()}\label{validate-for-save}}
!
! This method iterates on every key (attribute {\bf and} relation) and
! calls \method{validateValueForKey} for each of them, using the stored
! value as the parameter 'value'.
! \begin{notice}
! if you defined your own validation logic for some keys, they are called as
! well, as expected and seen above.
! \end{notice}
! You can also define your own global validation method, like:
! \begin{verbatim}
! from Modeling import Validation
! def validateForSave(self):
! "Validate "
! error=Validation.Exception()
! try:
! CustomObject.validateForSave(self)
! except Validation.Exception, error:
! error.aggregateException(error)
! # Your custom bizness logic goes here
! if self.getFirstName()=='John': # No John, except the One
! if self.getLastName()!='Cleese':
! error.aggregateError(Validation.CUSTOM_OBJECT_VALIDATION,
! Validation.OBJECT_WIDE_KEY)
! error.finalize() # raises, if appropriate
! \end{verbatim}
- Now suppose that our object \code{aWriter} stores \code{Jleese} for
- \var{lastName} and \code{John} for \var{firstName}. The dictionary of
- errors stored in the raised exception, after \method{validateForSave} is
- called, will be:
\begin{verbatim}
! { 'OBJECT_WIDE_VALIDATION':
! ['Validation of object as a whole failed',
! 'Custom validation of object as a whole failed'],
! 'lastName':
! ['Custom validation of key failed'],
! }
\end{verbatim}
! The value \constant{Validation.OBJECT_WIDE_KEY} is used to report global
! validation errors. You will find it {\bf as soon as an error has been
! detected while validating}. Here you find an other value for that key,
! \constant{Validation.CUSTOM_OBJECT_VALIDATION}, indicating that our own
! code did not validate the values as well. Note that the validation for
! key \var{lastName} has failed as well and is also reported.
!
! \begin{notice}[warning]
! {\bf IMPORTANT NOTE} -- contrary to what happens with methods
! \method{validate<AttributeName>}, the method \method{validateForSave()}
! we defined here overrides the definition inherited from
! \class{CustomObject}. Hence, it is very important not to forget calling
! the superclass' implementation, as described in the code above.
! \end{notice}
!
! \subsubsection{\method{validateForDelete()}\label{validate-for-delete}}
!
! TBD.
!
! \subsection{Misc.\label{customobject-misc}}
!
! A \class{Validation.ValidationException} object defines \method{__str__},
! so for the previous example, \code{str(error)} says::
!
\begin{verbatim}
! Validation for key OBJECT_WIDE_VALIDATION failed:
! - Validation of object as a whole failed
! - Custom validation of object as a whole failed
! Validation for key name failed:
! - Custom validation of key failed
! \end{verbatim}
!
--- 201,275 ----
\item \code{aBook.takeValueForKeyPath("Hugo", "author.lastName")} is
equivalent to \code{aBook.getAuthor().setLastName("Hugo")}
! \item \code{aBook.valuesForKeys(['title', 'price'])} is equivalent to
! \code{[aBook.getTitle(), aBook.getPrice()]}
\end{itemize}
! Of course, the objects' properties may always still be accessed
! using the getters and setters of your python objects,
! \section{Mixing KeyValueCoding and model's properties\label{mixing-model-props-and-kvc}}
! We'll see that dynamic manipulation of an object's properties and
! relationships can be completely generic, using the techniques we saw in the
! previous chapters.
+ Since we know how model's properties can be retrieved, and how an object can
+ be generically asked for a given property, we can combine these two techniques
+ to generically manipulate any object, for example to print informations on a
+ list of different objects:
\begin{verbatim}
! >>> ms=defaultModelSet()
! >>> objs=ec.fetch('Writer', qualifier='lastName=="Cleese"')
! >>> objs.extend(ec.fetch('Book'))
! >>> #
! ... # Now we will manipulate 'objs' without explicitly referring
! ... # to its method
! ...
! >>> for o in objs:
! ... print 'Object ',o
! ... for cp in ms.entityNamed(o.entityName()).classProperties_attributes():
! ... print ' %s: %s'%(cp.name(),o.valueForKey(cp.name()))
! Object (<Writer.Writer instance at 0x8485a04>) John Cleese
! age: 24
! lastName: Cleese
! firstName: John
! birthday: 1939-10-27 08:31:15.00
! Object <Book.Book instance at 0x8491f94>
! title: Gargantua
! id: 1
! price: None
! Object <Book.Book instance at 0x848a1fc>
! title: Bouge ton pied que je voie la mer
! id: 2
! price: None
! Object <Book.Book instance at 0x848f50c>
! title: Le coup du pere Francois
! id: 3
! price: None
! Object <Book.Book instance at 0x84a38b4>
! title: T'assieds pas sur le compte-gouttes
! id: 4
! price: None
\end{verbatim}
! We can achieve the same thing with \method{valuesForKeys()}:
\begin{verbatim}
! >>> for o in objs:
! ... print 'Object ',o
! ... cp_attrs=ms.entityNamed(o.entityName()).classProperties_attributes()
! ... cp_attrs_names=[cp.name() for cp in cp_attrs]
! ... print ' ',o.valuesForKeys(cp_attrs_names)
! Object (<Writer.Writer instance at 0x8485a04>) John Cleese
! [24, 'Cleese', 'John', <DateTime object for '1939-10-27 08:31:15.00' at 81984f0>]
! Object <Book.Book instance at 0x8491f94>
! ['Gargantua', 1, None]
! Object <Book.Book instance at 0x848a1fc>
! ['Bouge ton pied que je voie la mer', 2, None]
! Object <Book.Book instance at 0x848f50c>
! ['Le coup du pere Francois', 3, None]
! Object <Book.Book instance at 0x84a38b4>
! ["T'assieds pas sur le compte-gouttes", 4, None]
! \end{verbatim}
\ No newline at end of file
Index: ManipulatingGraphOfObjects.tex
===================================================================
RCS file: /cvsroot/modeling/ProjectModeling/Modeling/doc/UserGuide/ManipulatingGraphOfObjects.tex,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -d -r1.9 -r1.10
*** ManipulatingGraphOfObjects.tex 19 May 2003 16:05:16 -0000 1.9
--- ManipulatingGraphOfObjects.tex 4 Jul 2003 17:06:52 -0000 1.10
***************
*** 77,80 ****
--- 77,89 ----
\end{verbatim}
+ Alternatively, you can use the method \method{insert} ; both
+ \method{insert} and \method{insertObject} are completely equivalent, and
+ depending on your own feeling you may prefer one or the other.
+
+ \begin{verbatim}
+ newBook=Book()
+ ec.insert(newBook)
+ \end{verbatim}
+
\section{Fetching objects\label{ec-fetch-object}}
***************
*** 112,120 ****
As expected, the \class{EditingContext} is again the object to which we will
ask for the service. The corresponding method is
! \method{objectsWithFetchSpecification()}. This method requires a
! \class{FetchSpecification} object, which minimally identifies the entity of
! objects you want to fetch, and which can be qualified by a \class{Qualifier}
! object. This may sound complicated, but you will probably quickly
! agree that it is actually very straighforward.
\subsection{Simple fetch\label{ec-simple-fetch}}
--- 121,125 ----
As expected, the \class{EditingContext} is again the object to which we will
ask for the service. The corresponding method is
! \method{fetch()}.
\subsection{Simple fetch\label{ec-simple-fetch}}
***************
*** 123,180 ****
\begin{verbatim}
! from Modeling.FetchSpecification import FetchSpecification
!
! fetchSpec=FetchSpecification(entityName='Writer')
! objects=ec.objectsWithFetchSpecification(fetchSpec)
\end{verbatim}
! You see here that we first build a \class{FetchSpecification} bound to the
! entity \code{Writer}, identified by its name, then we simply pass that fetch
! specification to the editing context. That's it.
!
Now what if you want the \class{Writer} objects whose last name is
\code{'Hugo'}? That's not really more complicated:
\begin{verbatim}
! from Modeling.FetchSpecification import FetchSpecification
! from Modeling.Qualifier import qualifierWithQualifierFormat
!
! qualifier=qualifierWithQualifierFormat('lastName=="Hugo"')
! fetchSpec=FetchSpecification(entityName='Writer', qualifier=qualifier)
! objects=ec.objectsWithFetchSpecification(fetchSpec)
\end{verbatim}
! These three lines are all you need to fetch any object from the database: the
! FetchSpecification identifies the type of the objects you're fetching, and the
! qualifier describes them. Everything is then done automatically, i.e. the
! correct SQL statement(s) are built and executed and the objects are then built
! from the retrieved rows and given back to you in a sequence.
! In the next section, we will see more complete examples, but it basically
! always these three lines that you'll use for fetching objects.
! \subsection{More complicated fetching\label{ec-more-fetch}}
! Now we'll concentrate on qualifiers, so that you can see how to build you own,
! through some examples.
! \subsubsection{Pattern matching}
! you'll write:
\begin{verbatim}
! qualifier=qualifierWithQualifierFormat('lastName like "Hu*"')
\end{verbatim}
Available wildcards are \code{'*'} and \code{'?'}. The former matches any
! number of characters (including 0 --zero-- character), the latter one
occurrence of a character.
You can also use the operator \code{'caseInsensitiveLike'}:
\begin{verbatim}
! qualifier=qualifierWithQualifierFormat('lastName caseInsensitiveLike "hu?o"')
\end{verbatim}
will match: \code{'Hugo'}, \code{'Hulo'}, \code{'HUGO'}, \code{'hUXO'}, ...
! \subsubsection{Equality, comparisons}
When building your qualifiers, you can use the following operators:
\begin{itemize}
--- 128,182 ----
\begin{verbatim}
! objects=ec.fetch('Writer')
\end{verbatim}
! That's it.
Now what if you want the \class{Writer} objects whose last name is
\code{'Hugo'}? That's not really more complicated:
\begin{verbatim}
! objects=ec.fetch('Writer', qualifier='lastName=="Hugo"')
\end{verbatim}
! This is almost all you need to fetch any object from the database: just
! identify the type of the objects you're fetching, and the qualifier describing
! them. Everything is then done automatically, i.e. the correct SQL statement(s)
! are built and executed and the objects are then built from the retrieved rows
! and given back to you in a sequence.
! In the next sections, we will see more complete examples, but it basically
! always this line that you'll use for fetching objects.
! %\subsection{More complicated fetching\label{ec-more-fetch}}
! %
! %Now we'll concentrate on qualifiers, so that you can see how to build you own,
! %through some examples.
! \subsection{Pattern matching\label{ec-fetch-pattern-matching}}
! Suppose you want to get all the writers whose names begins with 'Hu', you'll
! write:
\begin{verbatim}
! objects=ec.fetch('Writer', qualifier='lastName like "Hu*"')
\end{verbatim}
Available wildcards are \code{'*'} and \code{'?'}. The former matches any
! number of characters (including 0 --zero-- character), the latter exactly one
occurrence of a character.
You can also use the operator \code{'caseInsensitiveLike'}:
\begin{verbatim}
! object=ec.fetch('Writer', qualifier='lastName caseInsensitiveLike "hu?o"')
\end{verbatim}
will match: \code{'Hugo'}, \code{'Hulo'}, \code{'HUGO'}, \code{'hUXO'}, ...
! Alternatively, you'd probably prefer to use a shorted alias for
! \code{caseInsensitiveLike}: \code{ilike}
! \begin{verbatim}
! object=ec.fetch('Writer', qualifier='lastName ilike "hu?o"')
! \end{verbatim}
!
! \subsection{Equality, comparisons\label{ec-fetch-operators}}
When building your qualifiers, you can use the following operators:
\begin{itemize}
***************
*** 189,197 ****
So, with this qualifier used to fetch \class{Writer} objects,
\begin{verbatim}
! qualifier=qualifierWithQualifierFormat('age >= 80')
\end{verbatim}
you'll get all the authors who are 80 years old or more.
! \subsubsection{Negating, Con- or disjoining qualifiers}
Now that we've seen all possible operators, we'll see that it is possible to
--- 191,199 ----
So, with this qualifier used to fetch \class{Writer} objects,
\begin{verbatim}
! objects=ec.fetch('Writer', qualifier='age >= 80')
\end{verbatim}
you'll get all the authors who are 80 years old or more.
! \subsection{Negating, Con- or disjoining qualifiers\label{ec-fetch-con-disjoin-and-negate}}
Now that we've seen all possible operators, we'll see that it is possible to
***************
*** 199,203 ****
\begin{verbatim}
! qual=qualifierWithQualifierFormat('lastName like "H*" AND age >= 80')
\end{verbatim}
will give you the author whose lastName begins with the capitalized letter
--- 201,205 ----
\begin{verbatim}
! objects=ec.fetch('Writer', qualifier='lastName like "H*" AND age >= 80')
\end{verbatim}
will give you the author whose lastName begins with the capitalized letter
***************
*** 206,210 ****
Likewise,
\begin{verbatim}
! qual=qualifierWithQualifierFormat('age<50 OR lastName like "????"')
\end{verbatim}
will give you the \class{Writer} objects who are less than 50 years old, or
--- 208,212 ----
Likewise,
\begin{verbatim}
! objects=ec.fetch('Writer', qualifier='age<50 OR lastName like "????"')
\end{verbatim}
will give you the \class{Writer} objects who are less than 50 years old, or
***************
*** 213,217 ****
Last, operator \code{'NOT'} negates the expression, so
\begin{verbatim}
! qual=qualifierWithQualifierFormat('NOT(age<50 OR lastName like "????")')
\end{verbatim}
will fetch the \class{Writer} objects who are older than 50 {\em and} whose
--- 215,219 ----
Last, operator \code{'NOT'} negates the expression, so
\begin{verbatim}
! objects=ec.fetch('Writer', qualifier='NOT(age<50 OR lastName like "????")')
\end{verbatim}
will fetch the \class{Writer} objects who are older than 50 {\em and} whose
***************
*** 220,224 ****
\begin{notice}
Operators \code{'AND'}, \code{'OR'} and \code{'NOT'} should be written with
! capitalized letters, while operators \code{'like'} and
\code{'caseInsensitiveLike'} should be written as-is (exact typo.)
\end{notice}
--- 222,226 ----
\begin{notice}
Operators \code{'AND'}, \code{'OR'} and \code{'NOT'} should be written with
! capitalized letters, while operators \code{'like'}, \code{ilike} and
\code{'caseInsensitiveLike'} should be written as-is (exact typo.)
\end{notice}
***************
*** 241,245 ****
\end{quote}
! \subsubsection{Dotted notation}
Last, it is possible to qualify the fetched objects, not only on their own
attributes, but also on their related objects' properties as well. The
--- 243,247 ----
\end{quote}
! \subsection{Dotted notation\label{ec-fetch-dotted-notation}}
Last, it is possible to qualify the fetched objects, not only on their own
attributes, but also on their related objects' properties as well. The
***************
*** 249,255 ****
\begin{verbatim}
! qual=qualifierWithQualifierFormat('author.pygmalion.lastName caseInsensitiveLike 'r*')
! fetchSpec=FetchSpecification(entityName='Book', qualifier=qual)
! objects=ec.objectsWithFetchSpecification(fetchSpec)
\end{verbatim}
--- 251,255 ----
\begin{verbatim}
! objects=ec.fetch('Book', qualifier='author.pygmalion.lastName ilike "r*"')
\end{verbatim}
***************
*** 261,269 ****
SELECT t0.id, t0.title, t0.FK_WRITER_ID, t0.PRICE
FROM BOOK t0
! INNER JOIN ( WRITER t1
! INNER JOIN WRITER t2
! ON t1.FK_WRITER_ID=t2.ID )
ON t0.FK_WRITER_ID=t1.ID
! WHERE t2.LAST_NAME LIKE 'R%'
\end{verbatim}
--- 261,269 ----
SELECT t0.id, t0.title, t0.FK_WRITER_ID, t0.PRICE
FROM BOOK t0
! INNER JOIN (WRITER t1
! INNER JOIN WRITER t2
! ON t1.FK_WRITER_ID=t2.ID )
ON t0.FK_WRITER_ID=t1.ID
! WHERE UPPER(t2.LAST_NAME) LIKE UPPER('r%')
\end{verbatim}
***************
*** 272,276 ****
If you manipulate a big database and wants to bind the result of a query which
! is built e.g. using your applicationGUI, you certainly do not want to allow
the users to fetch a whole table into memory just because they type \code{'*'}
instead of \code{'B*'} in the query string.
--- 272,276 ----
If you manipulate a big database and wants to bind the result of a query which
! is built e.g. using your application GUI, you certainly do not want to allow
the users to fetch a whole table into memory just because they type \code{'*'}
instead of \code{'B*'} in the query string.
***************
*** 280,298 ****
the objects.
! The \class{EditingContext}\footnote{and all classes conforming to the
! \class{ObjectStore} interface}, provides a dedicated method for that purpose:
\begin{verbatim}
! nb_of_objects=ec.objectsCountWithFetchSpecification(fetchSpec)
\end{verbatim}
returns the number of objects that would be returned if the method
! \method{objectsWithFetchSpecification()} is triggered with the very same
argument.
\subsection{Fetching and inheritance\label{ec-fetch-inheritance}}
! To be documented.
\section{Updating objects\label{ec-update-object}}
--- 280,348 ----
the objects.
! The \class{EditingContext}
! %\footnote{and all classes conforming to the \class{ObjectStore} interface}
! provides a dedicated method for that purpose:
\begin{verbatim}
! nb_of_objects=ec.fetchCount('Book', qualifier='...')
\end{verbatim}
returns the number of objects that would be returned if the method
! \method{fetch()} is triggered with the very same
argument.
\subsection{Fetching and inheritance\label{ec-fetch-inheritance}}
! (TBD: This section has to be rewritten -- for the moment being it consists
! mostly of a copy-paste of messages exchanged on the mailing-list)
!
! Suppose you have the following model:
! \begin{verbatim}
! Address <<-toAddresses---toEmployee-> Employee
! ^
! / \
! T
! |
! +--------------+
! | |
! Executive SalesClerk
! \end{verbatim}
!
! (This model is in fact the model \code{StoreEmployees} you'll find in the
! unittests shipped with the framework)
!
! \begin{itemize}
! \item An address object can be transparently linked to either an Employee, an
! Executive or a SalesClerk instance. There is nothing particular to do, this
! is automatically handled.
+ \item \code{address.toEmployee()} will automatically retrieve the right object
+ (being an instance of one of those three classes). Here again, no particular
+ action is needed, the framework handles it for you.
+ \item Now, when fetching, you can specify whether you want to fetch a single
+ class or its inheritance tree as well. Compare this, based on the test
+ database and model \code{StoreEmployees}:
+
+ \begin{verbatim}
+ >>> from StoreEmployees import Address
+ >>> from Modeling.EditingContext import EditingContext as EC
+ >>> ec = EC()
+ >>> qualifier='toAddresses.zipCode like "4*"'
+ >>> ec.fetch('Employee', qualifier)
+ []
+ >>> # Now fetch against the inheritance tree below 'Employee'
+ ... all_objects=ec.fetch('Employee', qualifier, isDeep=1)
+ >>> [(o.entityName(), o.getFirstName(),o.getLastName())
+ ... for o in all_objects]
+ [('SalesClerk', 'John Jr.', 'Cleese'),
+ ('SalesClerk', 'Jeanne', 'Cleese'),
+ ('Executive', 'John', 'Cleese')]
+ \end{verbatim}
+
+ As you can see, specifying {\bf \code{isDeep=1}} when fetching allows you to
+ fetch against the whole inheritance tree for a given entity (here,
+ \code{Employee}).
+
+ \end{itemize}
\section{Updating objects\label{ec-update-object}}
***************
*** 312,318 ****
\end{verbatim}
! Note that, before a deleted object is about to be made persistent, when
! its corresponding row in the database is about to be deleted, some logic
is triggered. For example, if this object still has some relationships but
these relationships are marked as \constant{CASCADE_DELETE}, the objects
--- 362,375 ----
\end{verbatim}
+ Alternatively, you can use the method \method{delete} ; both
+ \method{delete} and \method{deleteObject} are completely equivalent, and
+ depending on your own feeling you may prefer one or the other.
! \begin{verbatim}
! ec.delete(newBook)
! \end{verbatim}
!
! Note that, before a deleted object is about to be made persistent (i.e. when
! its corresponding row in the database is about to be deleted), some logic
is triggered. For example, if this object still has some relationships but
these relationships are marked as \constant{CASCADE_DELETE}, the objects
***************
*** 325...
[truncated message content] |