---
title: Dynamic Data Store
slug: cms-13/docs/dynamic-data-store
docTags: 
createdAt: 2026-07-30T20:22:01.166Z
---

Optimizely Dynamic Data Store (DDS) is an Object-Relational Mapper (ORM). It provides an API for saving, loading, and searching data in SQL Server. Use DDS to persist simple data structures without creating custom database tables. DDS ships as part of the Framework package.

When used with compile-time data types (.NET classes), properties with a public `getter` and a `setter` (the `setter` does not need to be public) are mapped to a column in a database table. For runtime data types, each property added to a `PropertyBag` is mapped in the same way.

DDS has the following advantages:

- Straightforward to use for simple data structures.
- Supports LINQ for querying data.
- Does not require custom tables, which simplifies upgrades and installations.
- Supports multiple database tables to isolate stores.
- Supports typed models and property bags.
- Includes a cache layer.

Avoid DDS for high-performance and high-scalability requirements or when storing large object graphs (for example, DDS does not support lazy loading). In these situations, store data in custom tables where the table design and API are optimized for a specific use case. Alternative technologies for SQL Server include Microsoft Entity Framework and NHibernate for .NET.

## DDS data type mapping

DDS maps data types to columns in a single database table. Understanding how mapping works helps you design data structures that store and retrieve efficiently.

The table contains multiple columns of each supported data type. When a data structure is saved, DDS maps the .NET CLR type of each property against an internal list of supported types.

DDS supports the following types of mapping:

### Inline mapping

Inline mapping maps a property of a class or `PropertyBag` directly to one of the supported database columns. The following types support inline mapping:

- `System.Byte` (and arrays of)
- `System.Int16`
- `System.Int32`
- `System.Int64`
- `System.Enum`
- `System.Single`
- `System.Double`
- `System.DateTime`
- `System.String`
- `System.Char` (and arrays of)
- `System.Boolean`
- `System.Guid`
- `EPiServer.Data.Identity`

### Collection mapping

A property is mapped as a collection if it implements the `System.IEnumerable` interface. Collection elements (keys and values for `System.IDictionary`) are stored in a special reference table.

Although `EPiServer.Data.Dynamic.PropertyBag` implements `System.IEnumerable`, DDS treats it as a reference type (see the following section).

### Reference mapping

Properties that cannot be mapped inline or as a collection (including `EPiServer.Data.Dynamic.PropertyBag`) are mapped as references. Their properties are mapped as a subtype, and a link row in the reference table connects the parent data structure to the child. This approach lets you save complex trees of data structures (object graphs) in DDS.

### Default table

The default DDS table is `tblBigTable`. It contains the following fixed (mandatory) columns:

- `pkId` – The store ID and primary key of each data structure stored.
- `Row` – The row index. Each structure may span one or more rows in the big table.
- `StoreName`  – The store name to which the data structure belongs.
- `ItemType` – The .NET CLR Type that contains the properties saved to the current row.

The default big table also contains the following optional columns:

- `BooleanXX` (where XX is 01 through to 05) x 5
- `IntegerXX` (where XX is 01 through to 10) x 10
- `LongXX` (where XX is 01 through to 05) x 5
- `DateTimeXX` (where XX is 01 through to 05) x 5
- `GuidXX` (where XX is 01 through to 03) x 3
- `FloatXX` (where XX is 01 through to 07) x 7
- `StringXX` (where XX is 01 through to 10) x 10
- `BinaryXX` (where XX is 01 through to 05) x 5
- `Indexed_Boolean01`
- `Indexed_IntegerXX` (where XX is 01 through to 03) x 3
- `Indexed_LongXX` (where XX is 01 through to 02) x 2
- `Indexed_DateTime01`
- `Indexed_Guid01`
- `Indexed_FloatXX` (where XX is 01 through to 03) x 3
- `Indexed_StringXX` (where XX is 01 through to 03) x 3
- `Indexed_Binary01` (not Oracle)

The columns whose names start with `Indexed` have database indexes created on them.

Add or remove columns in this table to suit the type of data you are saving. For example, if a data type contains more than ten strings, the eleventh through twentieth strings are stored in a second row. This causes a join at runtime when reading the data. Adding `String11`, `String12`, and so on to the big table reduces row overspill and increases performance. To add more indexes, create columns with names starting with `Indexed` and add a database index on each.

### Custom tables

Create a custom table when a data type benefits from a tailored column layout. For example, a type that contains only strings performs better in a dedicated table. Include the mandatory columns (`pkId`, `Row`, `StoreName`, `ItemType`) and add up to about 20 `StringXX` columns.

To use a custom table, add the `EPiServerDataTableAttribute` to your class and set the `TableName` property to the name of the custom table.

### SQL Server type mapping

The following table lists the database column types in the default big table and the .NET CLR inline types they map to:

| Database Column Type                   | .NET CLR “Inline” Types                                                    |
| -------------------------------------- | -------------------------------------------------------------------------- |
| `varbinary(max)`<br />`varbinary(900)` | `System.Byte[]`                                                            |
| `int`                                  | `System.Byte`, `System.Int16`, `System.Int32`, `System.Enum`               |
| `bigint`                               | `System.Int64`                                                             |
| `float`                                | `System.Single`, `System.Double`                                           |
| `datetime`                             | `System.DateTime`                                                          |
| `uniqueidentifier`                     | `System.Guid`                                                              |
| `nvarchar(max)`<br />`nvarchar(450)`   | `System.String`, `System.Char`, `System.Char[]`, `EpiServer.Data.Identity` |
| `bit`                                  | `System.Boolean`                                                           |

### Database views

Each store is represented in the database by a view. Use these views like any other database view, including cross-joining with other tables and views.

## Assembly and namespaces

All DDS classes reside in the `EPiServer.Data` assembly. Reference the appropriate namespace for the functionality you need.

The `EPiServer.Data` assembly contains the following main namespaces:

- `EPiServer.Data` – Contains core classes used in DDS, most notably the `Identity` class.
- `EPiServer.Data.Configuration` – Contains the configuration classes for DDS.
- `EPiServer.Data.Dynamic` – Contains the `DynamicDataStoreFactory` and `DynamicDataStore` classes and their support classes.

### Store management

Use the `DynamicDataStoreFactory` class to create, obtain, and delete stores. Access the singleton instance through the static `Instance` property. Alternatively, decorate .NET classes with `EPiServerDataStoreAttribute` and set `AutomaticallyCreateStore` to `true` to create stores automatically.

### Save and load data

Save and load data using compile-time data types (.NET classes) or runtime data types with the `EPiServer.Data.Dynamic.PropertyBag` class. DDS is divided into logical stores identified by name. Stores are not polymorphic: only one property set is saved per store. However, re-mapping stores through interfaces and template types provides a level of polymorphism.

### Search data

Search data in DDS using the following methods:

- **Simple Find method** – Find data structures by matching one or more name-value pairs with data in the store.
- **LINQ** – Use Microsoft Language Integrated Query technology to find data structures.
