Views: 8771
Number of votes: 6
Average rating:

Changes in Dynamic Data Store

There have been quite a few changes in the Dynamic Data Store since the CTP 2 version was released. Here are the highlights:

CreateStore & GetStore

The DynamicDataStore<T>.CreateStore,  DynamicDataStore<T>.GetStore and DynamicDataStore<T>.GetStoreForItem methods have been moved to the non-generic version of the class. This is because the code analysis tool we use, FxCop does not like static methods on generic classes. I suppose that when you think about it from an Intellisence perspective it makes more sense to be able to type DynamicDataStore then dot and see all the CreateStore, GetStore and GetStoreForItem methods regardless of whether they are generic or not.

Also regarding CreateStore, the confusing replaceExisting parameter has been removed. This means that CreateStore will always create the store if it doesn’t exist or return the existing one if it does. One point to note is that if the store does exist, an integrity check is made to ensure it’s mappings agree with the type bag or System.Type passed in. That means that there is a small overhead of calling CreateStore compared to GetStore when a store exists.

Why do we have both CreateStore and GetStore?

This is because CreateStore takes parameters which define the store mappings such as the type bag (not relevant for the generic variant) and a StoreDefinitionParameters instance which contains information about custom column mapping and column indexing (more about that later).

I would recommend the following pattern when using the DDS. In your app start / initialization code call CreateStore to ensure your store exists. Then in your main app code when saving, searching and loading objects call GetStore instead. This will both save on execution time and removed the need to spread store definition logic around your codebase.

StoreDefinition Class

The latest version sees the introduction of the StoreDefinition class. This replaces the old FieldMapper class and presents a clearer API for working with store metadata and is also the way you re-map a store when the shape of your type changes or you need to add or remove indexes. Re-mapping a store should go something like this:

   1: StoreDefinition myStore = StoreDefinition.Get("MyStore");
   2:  
   3: if (myStore != null)
   4: {
   5:     // See what version the store definition has to decide
   6:     // whether to update the mappings or not
   7:     if (myStore.Version < 2)
   8:     {
   9:         // Need upgrading to version 2 of my type
  10:         myStore.RenameField("MyOldPropName", "MyNewPropName");
  11:         myStore.Remap(typeof(MyType));
  12:         myStore.CommitChanges();
  13:     }
  14: }

One thing to note is that properties that have been renamed must be specified through the RenameField method BEFORE any calls the Remap. This is because Remap has no way of knowing that a property has been renamed and therefore will treat it as a remove of the property with the old name and an add of the property with the new name.

Loading Objects through a non-generic store

The DynamicDataStore (non generic version) used to have Load and LoadAsObject methods. Load always returned a PropertyBag instance and LoadAsObject returned an instance of the System.Type that was saved.

In the latest version this has been turned around. Load will always return an instance of the System.Type that was saved which may well be a PropertyBag if that was what was saved. LoadAsObject has died and been replaced by LoadAsPropertyBag which will always return a PropertyBag regardless of the original System.Type saved.

Indexing

At last the DDS supports indexing. This has been achieved by adding additional indexed columns onto the default Big Table which will only contain values that should be indexed. That is, if you don’t specify, your properties will not be mapped to the columns.

Your objects’ properties can be indexed in two ways:

1. Attribute on the property

   1: class MyType
   2: {
   3:     [EPiServerDataIndex]
   4:     public int MyCustomId
   5:     {
   6:         get;
   7:         set;
   8:     }
   9: }

2. Via the CreateStore and Remap API calls:

   1: StoreDefinitionParameters storeParams = new StoreDefinitionParameters();
   2: storeParams.IndexNames.Add("MyCustomId");
   3:  
   4: DynamicDataStore<MyType> s = DynamicDataStore.CreateStore<MyType>("MyStore", storeParams);

Custom Column Mapping

You can now specify which columns in a big table your properties are to be mapped against. This could be useful if you have a custom big table and one of the columns has a foreign key on it against another table in your database. You would then want the property on your type that represents this relationship to be mapped to this column. This can also be done via an attribute or API:

   1: [EPiServerDataColumn(ColumnName="MyForeignKeyColumn")]
   2: public int MyForeignKey
   3: {
   4:     get;
   5:     set;
   6: }
   1: StoreDefinitionParameters storeParams = new StoreDefinitionParameters();
   2: storeParams.ColumnNamesMap.Add("MyForeignKey", "MyForeignKeyColumn");
   3:  
   4: DynamicDataStore<MyType> s = DynamicDataStore.CreateStore<MyType>("MyStore", storeParams);

By the way, for both Indexes and Column Mapping you can use attributes and API at the same time for the same type and the results will be merged. Any discrepancies such as a property being mapped to two different columns will cause an InvalidOperationException.

Caching

A cache based upon the Http runtime cache has been developed for the DDS. This is very similar to the existing CMS cache for pages and will also work in a load balanced environment.

By default in EPiServer CMS 6, the http runtime cache is on. To remove it and disable caching for the DDS you will need to add some lines to your web.config file:

   1: <episerver.dataStore>
   2:   <cache defaultProvider="nullCacheProvider">
   3:     <providers>
   4:       <add name="nullCacheProvider" description="Does not cache" type="EPiServer.Data.Cache.NullCacheProvider, EPiServer.Data" />
   5:     </providers>
   6:   </cache>
   7: </dataStore>
   8: </episerver.dataStore>

You can of course write your own cache if you like. Derive a class from EPiServer.Data.Cache.CacheProvider and implement the abstract methods.

Import / Export support in CMS 6

You can now export and import items in the DDS in the normal CMS export / import mechanism. This will also work for Mirroring. Only programmatic support for selecting which items to export will exist initially but a UI may follow in a later release if the demand is there.

CMS 6 Page Objects

In CMS 6 the PageData class now has a new property (.NET property, not an EPiServer property) called PageObjects. This is a collection that can be used to associate objects with a CMS page. Obviously the underlying storage for the objects will be, yes you guessed it, the Dynamic Data Store. When the page is exported or mirrored, its Page Objects will also hang in there for the ride.

More about import / export for DDS items and Page Objects in another blog post shortly.

  Please login to post a comment