Copyright Johan Kronberg 2009-2024 Latest posts RSS feed X: johankronberg LinkedIn Profile GitHub: krompaco
Site generated by: Record Collector

Using Dynamic Data Store related to an Episerver 6 page

We decided to build a poll function using a Question page type and an Option page type to put below. For each option we thought the new Dynamic Data Store related to an Episerver page, the Page Object Manager, would be a neat thing to use as storage for the votes.

Here's the interesting code out of the rough first draft.

To be cool and to save some lines we added two generic extension methods for PageData:

public static void SavePageObject(this PageData pd, object obj, string key)
{
    PageObjectManager pageObjectManager = new PageObjectManager(pd);
    pageObjectManager.Save(key, obj);
}

public static T GetPageObject<T>(this PageData pd, string key)
{
    PageObjectManager pageObjectManager = new PageObjectManager(pd);

    try
    {
        return pageObjectManager.Load<T>(key);
    }
    catch
    {
        return default(T);
    }
}

Then we created two simple classes implementing IDynamicData so that they would "borrow" the big table's primary key setup:

public class Vote : IDynamicData
{
    public DateTime CreatedOn { get; set; }
    public string Fingerprint { get; set; }

    #region IDynamicData Members
    public Identity Id
    {
        get;
        set;
    }
    #endregion
}

public class VoteOption : IDynamicData
{
    public IList<Vote> Votes { get; set; }

    public VoteOption()
    {
        this.Votes = new List<Vote>();
    }

    #region IDynamicData Members
    public Identity Id
    {
        get;
        set;
    }
    #endregion
}

Looking in the database we found that most Episerver DDS implementations using classes had IList for collections so we went with that.

We found that knowing the key you use for storing objects makes it all a lot easier to work with. In this case we create the key using a prefix and the PageGUID of the Option page so retrieving the data is done like this:

var allVotes = new List<Vote>();

foreach (PageData option in allChildren)
{
    var voteOptionObject = option.GetPageObject<VoteOption>(string.Format("vote-{0}", option.PageGuid));

    if (voteOptionObject != null)
    {
        allVotes.AddRange(voteOptionObject.Votes);
    }
}

Saving a vote is done like this:

string key = string.Format("vote-{0}", voteOptionPage.PageGuid);
VoteOption voteOptionObject = voteOptionPage.GetPageObject<VoteOption>(key);

if (voteOptionObject == null)
{
    voteOptionObject = new VoteOption();
}

var vote = new Vote();
// Set props
voteOptionObject.Votes.Add(vote);
voteOptionPage.SavePageObject(voteOptionObject, key);

Of course removing a Vote is done in a similar way by just removing Vote objects from the Votes list before SavePageObject().

The nice thing about this class-with-a-collection-approach is that the first save with one item in the List results in three rows (one for the PageObjectManager referencing the page ID and your key, one VoteOption and one Vote linked to the VoteOption) but then every addition to the list is only one new Vote row.

If you were to save multiple objects right on top of the PageObjectManager using different keys you would have two rows for every vote and you would have to iterate all and sniff the type of the objects you got from the PageObjectManager.

Code is tested in Episerver CMS 6 R1. Should work in R2 too but note that there are some changes for the DDS there that can make the code a little cleaner.

Published and tagged with these categories: Episerver, ASP.NET, Development