Introduction to EPiServer Dynamic Data Store (DDS)

This article was migrated from an older iteration of our website, and it could deviate in design and functionality.


This post provides an introduction to the Dynamic Data Store, or DDS, which was introduced with EPiServer 6.

Estimated read time : 11 minutes

Jump to

Goal of the implementation

In this post we’ll go through the steps of implementing page comments using the Dynamic Data Store. Focus will be the data store, not the UI parts of commenting! :)

Add a reference to EPiServer.Data

In order to work with dynamic data in EPiServer you may want to add a reference to the EPiServer.Data assembly so you’ll be able to access classes in the EPiServer.Data and EPiServer.Data.Dynamic namespaces:

image

Requirements for our business object

Our business object in this case will be a Comment class.

It should support:

  • Adding new comments
  • Deleting comments
  • Retrieving all comments for a specific page

Creating the Comment class

We’ll create a new class called Comment and we’ll make it inherit the IDynamicData interface:

public class Comment : IDynamicData

Public properties of the Comment class

We’ll add some basic properties to our Comment class to:

  1. Store the actual comment
  2. Keep a reference to the commented page
  3. Maintain a unique GUID-based ID for each comment
/// <summary>
/// Gets or sets the time when the comment was created
/// </summary>
public DateTime Time { get; set; }
 
/// <summary>
/// Gets or sets the commented page's ID
/// </summary>
public int PageID { get; set; }
 
/// <summary>
/// Gets or sets the username of the person who commented
/// </summary>
public string Username { get; set; }
 
/// <summary>
/// Gets or sets the actual comment text
/// </summary>
public string Text { get; set; }
 
/// <summary>
/// Gets or sets the ID of the comment
/// </summary>
public Identity Id { get; set; }

Initializing the Comment class

We’ll create an Initialize() method which will be called from the constructors to set default property values:

protected void Initialize()
{
// Generate a new ID
Id=Identity.NewIdentity(Guid.NewGuid());
 
// Set property values
Time=DateTime.Now;
 
// Default string properties
Username=string.Empty;
Text=string.Empty;
}

Constructors for the Comment class

Next we’ll add the constructors for the Comment class. Note that a public, parameter-less constructor is required to support serialization to the Dynamic Data Store:

// Parameter-less constructor required for the dynamic data store
public Comment()
{
Initialize();
}
 
public Comment(int pageId, string username, string text)
{
Initialize();
 
// Set property values
PageID=pageId;
Username=username;
Text=text;
}

Save comments to the Dynamic Data Store

Our first requirement is the ability to save comments to the data store. For this purpose we’ll add a Save() method to the Comment class.

It creates a new DynamicDataStore for the Comment type (if one doesn’t exist) and then saves the current instance to it:

/// <summary>
/// Save the comment
/// </summary>
public void Save()
{
// Create a data store (but only if one doesn't exist, we won't overwrite an existing one)
DynamicDataStore<Comment> store = DynamicDataStore<Comment>.CreateStore(false);
 
// Save the current comment
store.Save(this);
}

Delete a comment from the Dynamic Data Store

Next we’ll add a method for deleting a specific comment:

/// <summary>
/// Delete the comment permanently
/// </summary>
/// <param name="comment"></param>
public static void Delete(Comment comment)
{
// Create a data store (but only if one doesn't exist, we won't overwrite an existing one)
DynamicDataStore<Comment> store = DynamicDataStore<Comment>.CreateStore(false);
 
// Delete the specified comment
store.Delete(comment.Id);
}

Retrieve comments from the Dynamic Data Store

To retrieve all comments for a specific page we’ll add a GetComments() method.

Because of the Dynamic Data Store’s excellent support for LINQ we’ll use LINQ to query the data store:

/// <summary>
/// Get all comments for a specific page
/// </summary>
/// <param name="pageLink"></param>
/// <returns></returns>
public static List<Comment> GetComments(PageReference pageLink)
{
// Get a data store for comments 
DynamicDataStore<Comment> store = DynamicDataStore<Comment>.CreateStore(false);
 
// Retrieve comments for the specified page
var comments = from c in store
where c.PageID==pageLink.ID
select c;
 
// Return empty collection if no commentx exist
if (comments==null)
return new List<Comment>();
 
return comments.ToList<Comment>();
}

Trying out a simple comment form

To take the new Comment class out for a spin I added a (highly trivial) user control to the website’s Master page.

The markup for the user control looks like this:

<style type="text/css">
label { font-weight: bold; display: block; }
input { display: block }
input.textbox, textarea { width: 280px; border: solid 1px #999; margin: 5px 0 10px 0 }
</style>
 
<div class="commentform">
<h1>Add comment</h1>
 
<asp:Label Text="Name:" AssociatedControlID="txtName" runat="server" />
<asp:TextBox CssClass="textbox" ID="txtName" runat="server" />
<asp:Label Text="Comment:" AssociatedControlID="txtComment" runat="server" />
<asp:TextBox TextMode="MultiLine" MaxLength="50" Rows="7" ID="txtComment" runat="server" />
<asp:Button CssClass="button" Text="Save comment" OnClick="btnSave_Click" ID="btnSave" runat="server" />
 
<h1>Comments:</h1>
 
<asp:Repeater ID="rptComments" runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<strong><%# Eval("Username") %></strong>
wrote (<%# Eval("Time") %>):
<%# Eval("Text") %></li>
</ItemTemplate>
<FooterTemplate>
</ul><asp:Button CssClass="button" Text="Delete all" OnClick="btnDeleteAll_Click" ID="btnDeleteAll"
runat="server" />
</FooterTemplate>
</asp:Repeater>
</div>

The comment form in action

Here’s what the user control looks like in action (note that this screenshot was taken after I had added a comment to the current page):

image

The logic behind the comment form

When the user control loads it populates the list of comments for the current page (if there are any):

protected void PopulateCommentList()
{
// Get all comments for the current page
List<Comment> comments = Comment.GetComments(CurrentPage.PageLink);
 
// Databind repeater (if comments exist)
if (comments.Count>0)
{
rptComments.DataSource=comments;
rptComments.DataBind();
}
}

To add a new comment the user would enter its name and comment text in the text boxes. We don’t worry about any validation in this case, instead we’ll just hook up the following to the Click event of the Save comment button:

protected void btnSave_Click(object sender, EventArgs e)
{
// Create new comment
Comment comment = new Comment()
{
Username=txtName.Text,
Text=txtComment.Text,
PageID=CurrentPage.PageLink.ID
};
 
// Save the comment
comment.Save();
 
// Refresh the comments list
PopulateCommentList();
}

Oh, I added the Delete all button for testing purposes. It simply calls a little helper method I added to the Comment class.

Essentially it iterates over all comments for the specified page and calls the Delete() method of our Comment class:

/// <summary>
/// Delete all comments for a specific page
/// </summary>
/// <param name="pageLink"></param>
public static void ClearComments(PageReference pageLink)
{
foreach (Comment c in GetComments(pageLink))
{
Delete(c);
}
}

Further reading

Check out Allan Thraen’s DDS sample for page ratings.