Storage Definitions
In most cases, a persistent class includes a storage definition, which describes the global structure that InterSystems IRIS® data platform uses when it saves data for the class or reads saved data for the class.
This page explains the role of the storage definition and of the storage class used by the storage definition and explains what happens if the class definition changes.
Introduction to Storage Definitions
When you define and compile a persistent class, InterSystems IRIS generates a storage definition for it, adding the storage definition to the end of the class definition. The following shows an example storage definition:
Storage Default
{
<Data name="PresidentDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>Name</Value>
</Value>
<Value name="3">
<Value>BirthYear</Value>
</Value>
<Value name="4">
<Value>Bio</Value>
</Value>
</Data>
<DataLocation>^GlobalsTest.PresidentD</DataLocation>
<DefaultData>PresidentDefaultData</DefaultData>
<IdLocation>^GlobalsTest.PresidentD</IdLocation>
<IndexLocation>^GlobalsTest.PresidentI</IndexLocation>
<StreamLocation>^GlobalsTest.PresidentS</StreamLocation>
<Type>%Storage.Persistent</Type>
}
Notice the <Type> element, which specifies the storage class (%Storage.Persistent in this example).
Another page more closely examines the globals referred to by the storage definition; for now, simply notice that the storage definition describes how the globals are organized (for example, which subscript contains data for each property).
A persistent class can actually contain multiple storage definitions but only one can be active at a time. The active storage definition is specified using the StorageStrategy keyword of the class, not described here. By default, a persistent class has a single storage definition called Default.
Storage Classes
The %PersistentOpens in a new tab class provides the high-level interface for storing and retrieving objects in the database. The actual work of storing and loading objects is governed by a storage class. As shown in the previous example, a storage definition (part of the class definition) specifies the storage class to use.
The storage class generates the actual internal methods used to store, load, and delete objects in a database. These internal methods are the storage interface, which includes internal methods such as %LoadData(), %SaveData(), and %DeleteData(). Applications never call these methods directly; instead they are called at the appropriate time by the methods of the persistence interface (such as %OpenId() and %Save()).
There are two storage classes:
-
%Storage.Persistent, which is the default storage class used by persistent objects. It automatically creates and maintains a default storage structure for a persistent class.
New persistent classes automatically use the %Storage.Persistent storage class. The %Storage.Persistent class lets you control certain aspects of the storage structure used for a class by means of the various keywords in the storage definition.
Refer to the Class Definition Reference for details on the various storage keywords.
Also see Extent Definitions for information on the MANAGEDEXTENT class parameter.
-
%Storage.SQL, which a special storage class that uses generated SQL SELECT, INSERT, UPDATE, and DELETE statements to provide object persistence. %Storage.SQL is typically used for:
-
Mapping objects to preexisting global structures used by older applications.
-
Storing objects within an external relational database using the SQL Gateway.
%Storage.SQL does not automatically support schema evolution or multi-class extents.
-
Schema Evolution
The storage definition for a class is generated when the class is first compiled. When you compile a persistent (or serial) class that uses the default %Storage.Persistent storage class, the class compiler analyzes the properties defined by the class and automatically uses them in the storage definition.
Similarly, when you add properties, the class compiler updates the storage definition to provide access to these properties. When you remove properties, their descriptions within the storage definition remain unchanged.
This automatic process is schema evolution, and the goal is to safely preserve access to your data. Schema evolution does not apply to classes that use %Storage.SQL.
Resetting a Storage Definition
During the development process, you are likely to need to reset the storage definition of your classes, for reasons such as these:
-
You may make many modifications to your persistent classes: adding, modifying, and deleting properties. As a result, you may end up with a fairly convoluted storage definition as the class compiler attempts to maintain a compatible structure.
-
Also, class projection, such as for SQL, occurs after compilation. If a class compiles properly and then projection fails, InterSystems IRIS does not remove the storage definition.
To reset a storage definition, delete the storage definition from the class and then recompile the class.
Also delete all sample data for the class. Or if there is existing data you need to keep, you must migrate it to the new global structure.
Redefining a Persistent Class That Has Stored Data
During the development process, it is common to redefine your classes. If you have already created sample data for the class, note the following points:
-
The compiler has no effect on the globals that store the data for the class.
(In fact, when you delete a class definition, its data globals are untouched. If you no longer need these globals, delete them manually.)
-
If you add or remove properties of a class but do not modify the storage definition of the class, then all code that accesses data for that class continues to work as before. See Schema Evolution.
-
If you do modify the storage definition of the class, then code that accesses the data may or may not continue to work as before, depending on the nature of the change.
-
If you change the class from non-sharded to sharded or vice-versa, your existing data may become inaccessible.
-
If you modify a property definition in a way that causes the property validation to be more restrictive, then you will receive errors when you work with objects (or records) that no longer pass validation. For example, if you decrease the MAXLEN parameter for a property, then you will receive validation errors when you work with an object that has a value for that property that is now too long.