[[Property:uuid|EA781CE6-3452-4EEF-BF05-47D94FC88A3D]] [[Property:weight|3]] [[Property:title|Persistence, storage, and retrieval]] Most object-oriented applications need the ability to store object structures on persistent storage for later retrieval, and to transfer such object structures to other applications. Eiffel offers a full persistence mechanisms serving these needs. =Persistence completeness= A fundamental requirement on object persistence mechanisms is the ''Persistence Completeness'' rule, stated as follows in ''[[Eiffel: The Language]]'':
Whenever an object is stored into an external file, the stored content contains all the dependents of that object. Conversely, retrieving a previously stored object also retrieves all its dependents.
Storing an object just by itself would usually result in wrong semantics: most objects contain references to other objects, which must also be stored and retrieved with it. The persistence completeness rule ensures that this is always the case. It also means, of course, that features used for storing and retrieving objects must do much more than simple input and output; they must perform complete traversals of object structures.The Eiffel persistence mechanism applies Persistence Completeness. =Varieties of store operations= Different variants of the store operation are available: '''session''', '''basic''' and '''independent''' store * '''Session''' store produces the most compact structure in the resulting files; but the resulting structure is dependent on the current execution of the system which executes the store operation (''System'' is taken here, as elsewhere in this documentation, in its Eiffel sense of an executable assembly of classes, compiled together with the help of a configuration file.) * '''Basic''' store is like session store with the difference that the resulting structure is dependent on the system which executes the store operation (i.e. only the system creating the persistent version can retrieve it.) * On the other hand, '''independent''' store allows a system running on a computer with a certain architecture to retrieve, without any explicit conversion operation, object structures stored by a system running on a machine of a completely different architecture. In addition, independent store lets you retrieve an old version of the object that was saved (see more details in the recoverable section below.) =Using the storage and retrieval facilities= Historically, the persistence mechanism was offered via the helper class [[ref:libraries/base/reference/storable_chart|STORABLE]] which you could use as an ancestor whenever you wanted to store and retrieve objects. Via this class you would have access to
store_object (o: ANY; p: PATH)
-- Store object `o` into file located in `p`.
local
f: RAW_FILE
do
create f.make_with_path (p)
f.open_write
f.independent_store (o)
f.close
end
Then to retrieve the object you would write the following:
retrieve (p: PATH)
-- Retrieve object stored in file located in `p`.
local
f: RAW_FILE
do
create f.make_with_path (p)
f.open_read
if attached {MY_TYPE} io_medium.retrieved as data then
-- Retrieved result is of expected type.
-- Proceed with processing of result,
-- typically with calls of the form `data.some_feature'.
else
-- Result was not of expected type MY_TYPE.
end
f.close
end
If the structure in the file has been corrupted and
store_object (o: ANY; p: PATH)
-- Store object `o` into file located in `p`.
local
f: RAW_FILE
writer: SED_MEDIUM_READER_WRITER
do
create f.make_with_path (p)
f.open_write
create writer.make_for_writing (l_file)
store (o, writer)
f.close
end
Then to retrieve the object you would write the following:
retrieve (p: PATH)
-- Retrieve object stored in file located in `p`.
local
f: RAW_FILE
reader: SED_MEDIUM_READER_WRITER
do
create f.make_with_path (p)
f.open_read
create reader.make_for_reading (f)
if attached {MY_TYPE} retrieved (reader, False) as data then
-- Retrieved result is of expected type.
-- Proceed with processing of result,
-- typically with calls of the form `data.some_feature'.
else
-- Result was not of expected type MY_TYPE.
end
f.close
end
In case of an error during retrieval, no objects will be returned and instead the query
correct_mismatch
-- Attempt to correct object mismatch during retrieve using `mismatch_information'.
do
-- In version 5.1 and earlier, `content', `keys' and `deleted_marks'
-- were of base class ARRAY. In 5.2 we changed it to be a SPECIAL for
-- efficiency reasons. In order to retrieve an old HASH_TABLE we
-- need to convert those ARRAY instances into SPECIAL instances.
-- Convert `content' from ARRAY to SPECIAL.
if attached {ARRAY [G]} mismatch_information.item ("content") as l_temp then
content := l_temp.area
end
-- Convert `keys' from ARRAY to SPECIAL.
if attached {ARRAY [H]} mismatch_information.item ("keys") as l_temp then
keys := l_temp.area
end
-- Convert `deleted_marks' from ARRAY to SPECIAL.
if attached {ARRAY [BOOLEAN]} mismatch_information.item ("deleted_marks") as l_temp then
deleted_marks := l_temp.area
end
if content = Void or keys = Void or deleted_marks = Void then
-- Could not retrieve old version of HASH_TABLE. We throw an exception.
Precursor {TABLE}
end
end
Note the use of