Map stores
Describes mapping store types.
Compile time type mapping
When instances of a compile time data type (.NET classes excluding EPiServer.Data.Dynamic.PropertyBag
and classes implementing System.IEnumerable
) are saved in the Dynamic Data Store, their “inline” properties are mapped to columns in the “big table”. This is known logically as a store.
Default mapping
The default algorithm for mapping .NET classes (excluding EPiServer.Data.Dynamic.PropertyBag
and classes implementing System.IEnumerable
) to a store is as follows:
- Property must have a getter and setter
- Property must be marked public (although the setter can marked non-public if desired)
- All other properties are ignored and not saved in the Dynamic Data Store
Custom mapping
You can override the default mapping behavior. This is useful if you do not want certain public properties to be mapped or do want certain non-public properties to be mapped.
To use custom mapping, you need to add the System.Runtime.Serialization.DataContactAttribute
to your class definition. In this case, only properties marked with the System.Runtime.Serialization.DataMemberAttribute
will be mapped and saved in the Dynamic Data Store regardless of the accessibility status. They must still however have both a getter and setter.
See the MappingWithDataContract
class in the DDS sample project for examples.
You may want to save an object of an existing class that has already been marked with DataContactAttribute
and its member properties with DataMemberAttribute
. One problem might be that the use of these properties does not match the desired behavior when an object instance is saved in the Dynamic Data Store. In these cases, you can also add the EPiServerDataContractAttribute
to the class definition and EPiServerDataMemberAttribute
to the properties to be saved. The Dynamic Data Store will use these attributes in preference to the Microsoft ones to resolve the conflict.
See the MappingWithEPiServerDataContract
class in the DDS sample project for examples.
Type handlers
Some classes in the .NET Framework do not have properties that the Dynamic Data Store can use to extract the value, save to the database and then re-inflate an instance with the value from the database. If you want to use such a type as a property on a class that will be saved to the Dynamic Data Store, you need to register a Type Handler for it.
A good example of this is the System.Uri
class. This class only has read-only properties and therefore saving an instance to the Dynamic Data Store without a Type Handler is meaningless as no data will be stored for it.
See the MappingWithTypeHandler
class in the DDS sample project for examples.
Map runtime data type (PropertyBag)
Properties saved using PropertyBags
are mapped as if the properties were public members properties on a normal .NET class. PropertyBags
can be mapped in the following ways:
- Implicit is the first time a
PropertyBag
is saved to a new store the store mappings are inferred from the properties in thePropertyBag
. - Explicit is a mapping dictionary which is passed to the
DynamicDataStoreFactory.CreateStore
method detailing the store mapping. The main advantage of this is that all properties that can be potentially saved in this store are mapped, as opposed to the first time aPropertyBag
is saved which may not have all potential values.
See the ImplicitDynamicMapping
and ExplicitDynamicMapping
classes in the DDS sample project for examples.
Store remapping
From time to time you may need to change the structure of your data. This can mean adding, removing or changing properties on your .NET classes or PropertyBags.
The Dynamic Data Store is quite flexible when it comes to accepting changes to types that have been saved in a store.
You can remap .NET classes to stores in the following ways:
- Using attributes on the class.
- Using attributes via the
StoreDefinition
class. Remapping stores that are not represented by a .NET class can only be done with theStoreDefinition
class.
Remap using class attributes
A .NET class whose instances will be saved in the Dynamic Data Store can be optionally decorated with the EPiServerDataStoreAttribute
. In these cases, set the AutomaticallyRemapStore
property to true. When the Optimizely application starts, it scans for all classes with this attribute and automatically remaps the .NET class to the store, if needed. Any properties that have been renamed MUST be marked with the EPiServerDataPropertyRenameAttribute
attribute, otherwise the remap treats them as if one property was removed (with the old name) and one added (with the new name).
Remap using StoreDefinition class
To remap a store, obtain the store definition of a store either via the StoreDefinition
property of a DynamicDataStore
instance or via the StoreDefinition.Get
method.
You can then call the Rename
and Remap
methods to update the store's mappings. You should call Rename
before Remap
, otherwise properties that were renamed in the data type are treated as if one property was removed and one added.
Finally, call the CommitChanges
method of StoreDefinition
to update the store's meta information in the database. If a DynamicDataStore
instance reference is held, then its Refresh
method should be called to align its in-memory copy of the store definition with the one committed to disk.
Remap rules
These rules are followed when remapping stores:
- Properties removed from the type definition are removed from the store.
Note
The data itself for the removed property remain intact in the big table. It is only the “view” of the data that is changed.
- Properties added to the type definition are added to the store.
- Properties with the same name but different data types are checked for compatibility. In the case where both old and new property data types are ‘inline’, the database used must be able to convert from the old database data type to the new database data type. If a collection or reference type is changed, then the new property type must either be assignable (using
System.Type.IsAssignableFrom
) or the old type must be convertible to the new type. The old type supportsSystem.IConvertible
and theSystem.Convert.ChangeType
succeeds in converting an instance of the old type to an instance of the new type.
See the StoreReMapping
class for examples of store re-mapping and the PropertyReName
class for how to update mappings when a property has been renamed on a type, both in the Dynamic Data Store SDK.
Map types to specific stores
It can be convenient to save instances of a Type in the same store, regardless of where those instances are in an object graph. You have the following options:
- Global Mapping – Use the
EPiServer.Data.Dynamic.GlobalTypeToStoreMap.Instance
methods to add and remove a mapping or add anEPiServer.Data.Dynamic.EPiServerDataStoreAttribute
to the .NET class. When this is used, all instances of the registered Type are saved in the store with the specified name. - Local Mapping – A delegate is passed to the
DynamicDataStore
orDynamicDataStore<T>
Save method. This delegate will be called for all “reference” properties and collection items that are references. The delegate should return the name of the store to save the item in. This allows extra flexibility to steer instances of a Type into different stores depending on the context and how they are used.
Note
The store top level item, that is, the object passed to the
DynamicDataStore
Save
method, is always saved in the current store (the storeSave
is being called on) regardless of the name of that store. This effectively overrides theType
toStore
mapping mechanism.
Example:
- A global
Type
toStore
mapping is added so all instances of the Type “Person” are saved in a store called “People”. - A store is created/obtained with the name “MyPeople”.
- An instance of a Person Type is saved in the store obtained in step 2. This instance has properties that are also Person instances.
Result: The top level Person is saved in the “MyPeople” store but all other instances of the Person Type in the object graph are saved in the “People” store (because of the global mapping).
To adhere to the global Type to Store mappings you should create or obtain your top level store by calling DynamicDataStoreFactory.Create
or GetStore
with just the type and not a store name.
See the UsingGlobalTypeToStoreMapping
and UsingLocalTypeToStoreMapping
classes in the DDS sample project for more details.
Map stores to custom big tables
In the same way as it may be convenient to map a Type
to a Store
, it may also prove convenient to map a store to a custom big table. See the Big Table section in the Dynamic Data Store topic for more details.
The UsingGlobalStoreToTableMapping
class in the DDS sample project demonstrates this technique.
Updated about 1 month ago