Try our conversational search powered by Generative AI!

smithsson68@gmail.com
Nov 23, 2009
  10890
(3 votes)

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.

Nov 23, 2009

Comments

Sep 21, 2010 10:32 AM

Very cool stuff :). Looking forward to playing with it!
/ Frederik Vig

Sep 21, 2010 10:32 AM

Fantastic
/ Yagnik

Please login to comment.
Latest blogs
Optimizely and the never-ending story of the missing globe!

I've worked with Optimizely CMS for 14 years, and there are two things I'm obsessed with: Link validation and the globe that keeps disappearing on...

Tomas Hensrud Gulla | Apr 18, 2024 | Syndicated blog

Visitor Groups Usage Report For Optimizely CMS 12

This add-on offers detailed information on how visitor groups are used and how effective they are within Optimizely CMS. Editors can monitor and...

Adnan Zameer | Apr 18, 2024 | Syndicated blog

Azure AI Language – Abstractive Summarisation in Optimizely CMS

In this article, I show how the abstraction summarisation feature provided by the Azure AI Language platform, can be used within Optimizely CMS to...

Anil Patel | Apr 18, 2024 | Syndicated blog

Fix your Search & Navigation (Find) indexing job, please

Once upon a time, a colleague asked me to look into a customer database with weird spikes in database log usage. (You might start to wonder why I a...

Quan Mai | Apr 17, 2024 | Syndicated blog

The A/A Test: What You Need to Know

Sure, we all know what an A/B test can do. But what is an A/A test? How is it different? With an A/B test, we know that we can take a webpage (our...

Lindsey Rogers | Apr 15, 2024

.Net Core Timezone ID's Windows vs Linux

Hey all, First post here and I would like to talk about Timezone ID's and How Windows and Linux systems use different IDs. We currently run a .NET...

sheider | Apr 15, 2024