HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Map stores

Map .NET classes and PropertyBags to Dynamic Data Store (DDS) stores, remap store structures, and route types to specific stores or custom big tables.

Dynamic Data Store (DDS) maps .NET data types to database columns so that object properties persist and restore automatically. This article covers compile-time and runtime type mapping, store remapping, and routing types to specific stores.

Compile-time type mapping

Define how DDS translates .NET class properties into store columns at compile time.

When instances of a compile-time data type (.NET classes excluding EPiServer.Data.Dynamic.PropertyBag and classes implementing System.IEnumerable) are saved in Dynamic Data Store, their "inline" properties map to columns in the "big table." This combination of mapped columns is known logically as a store.

Default mapping

Understand which properties DDS maps automatically without additional configuration.

The default algorithm for mapping .NET classes (excluding EPiServer.Data.Dynamic.PropertyBag and classes implementing System.IEnumerable) to a store follows these rules:

  • Property must have a getter and setter
  • Property must be marked public (although the setter can mark non-public if desired)
  • Other properties are ignored and not saved in the Dynamic Data Store

Custom mapping

Override the default mapping to include non-public properties or exclude public ones.

Custom mapping controls which properties DDS persists. Add the System.Runtime.Serialization.DataContractAttribute to the class definition. Only properties marked with the System.Runtime.Serialization.DataMemberAttribute are then mapped and saved in Dynamic Data Store, regardless of accessibility. They must still have a getter and setter.

Some existing classes already use DataContractAttribute and DataMemberAttribute for other purposes. If the existing attribute configuration does not match the desired DDS behavior, add the EPiServerDataContractAttribute to the class definition and EPiServerDataMemberAttribute to the properties to save. Dynamic Data Store uses these attributes in preference to the Microsoft ones to resolve the conflict.

Type handlers

Register type handlers for .NET classes whose properties DDS cannot extract and restore automatically.

Some .NET Framework classes lack writable properties that DDS requires to extract, save, and restore values. To use such a type as a property on a class saved to Dynamic Data Store, register a type handler for it.

For example, the System.Uri class has only read-only properties. Saving an instance to Dynamic Data Store without a type handler stores no data.

Map runtime data type (PropertyBag)

Map dynamic property sets at runtime using PropertyBag objects instead of compiled .NET classes.

Properties saved using PropertyBag objects are mapped as if they were public member properties on a standard .NET class. PropertyBag objects support two mapping approaches:

  • Implicit – The first time a PropertyBag is saved to a store, DDS infers the store mappings from the properties in the PropertyBag.
  • Explicit – A mapping dictionary is passed to the DynamicDataStoreFactory.CreateStore method to define the store mapping. This approach maps all properties that the store will accept, not only those present on the first save.

Store remapping

Update store mappings when .NET class properties or PropertyBag structures change.

Data structures evolve over time. Changing properties on .NET classes or PropertyBag objects requires remapping the store. Dynamic Data Store accepts structural changes to types saved in a store.

Remap .NET classes to stores using the following approaches:

  • Using attributes on the class.
  • Using attributes with the StoreDefinition class. Remapping stores that are not represented by a .NET class can only be done with the StoreDefinition class.

Remap using class attributes

Automate store remapping at application startup by decorating a .NET class with EPiServerDataStoreAttribute.

Set the AutomaticallyRemapStore property to true on the attribute. When Optimizely starts, it scans for classes with this attribute and remaps the .NET class to the store if needed. Any renamed properties must be marked with the EPiServerDataPropertyRenameAttribute attribute. Otherwise, the remap treats them as if one property was removed (with the old name) and one was added (with the new name).

Remap using StoreDefinition class

Remap stores programmatically using the StoreDefinition class, especially for stores not represented by a .NET class.

Obtain the store definition through the StoreDefinition property of a DynamicDataStore instance or through the StoreDefinition.Get method.

Call RenameProperty before Remap to update the store mappings. Otherwise, renamed properties in the data type are treated as if one property was removed and another was added.

After remapping, call CommitChanges on StoreDefinition to update the store metadata in the database. If a DynamicDataStore instance reference exists, call its Refresh method to align the in-memory store definition with the committed version.

Remap rules

DDS follows these rules when remapping stores:

  1. Properties removed from the type definition are removed from the store.
    📘

    Note

    The data for the removed property remains intact in the big table. Only the “view” of the data changes.

  2. Properties added to the type definition are added to the store.
  3. Properties with the same name but different data types are checked for compatibility. When 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 one. If a collection or reference type is changed, then the new property type must be assignable (using System.Type.IsAssignableFrom) or the old type must be convertible to the new type. The old type supports System.IConvertible and the System.Convert.ChangeType succeeds in converting an instance of the old type to an instance of the new type.

For examples of store remapping and property renaming, see the Dynamic Data Store SDK samples.

Map types to specific stores

Route all instances of a type to the same store, regardless of their position in an object graph.

Two mapping options control where type instances are saved:

  1. Global mapping – Use the EPiServer.Data.Dynamic.GlobalTypeToStoreMap.Instance methods to add or remove a mapping. Alternatively, add EPiServer.Data.Dynamic.EPiServerDataStoreAttribute to the .NET class. Instances of the registered type are then saved in the store with the specified name.
  2. Local mapping – Pass a delegate to the DynamicDataStore or DynamicDataStore<T> Save method. This delegate is called for "reference" properties and collection items that are references. The delegate returns the store name for the item, allowing instances of a type to be routed to different stores based on context.
📘

Note

The store top-level item (the object passed to the DynamicDataStore Save method) is always saved in the current store, regardless of type-to-store mappings. This overrides the mapping mechanism for the top-level object.

Example:

  1. A global type-to-store mapping is added so instances of the Person type are saved in a store called People.
  2. A store is created or obtained with the name MyPeople.
  3. An instance of Person 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 other Person instances in the object graph are saved in the People store because of the global mapping.

To follow the global type-to-store mappings, create or obtain the top-level store by calling DynamicDataStoreFactory.CreateStore or GetStore with just the type and not a store name.

Map stores to custom big tables

Route a store to a custom big table for dedicated storage of specific data types.

A store can map to a custom big table, similar to how a type maps to a store. See the Big Table section in the Dynamic Data Store topic for details.