---
title: Extend comments with composites
slug: cms-12/api/extending-comments-with-composites
docTags: 
createdAt: 2026-08-07T16:45:43.000Z
---

You may need to associate additional information with a comment to support your application's use cases. A common example is the implementation of a product review.

A review is fundamentally a comment centered around the reviewer's commentary and is often accompanied by additional information. It may refer to a rating (or series of ratings) or include purchase details. The Optimizely Community API lets you extend a comment with your design data to achieve such solutions by creating a *Composite*. See also *Composites* in [Discover the platform](docId\:NKmGS-fLtRQIYLEWZfb69).

### Add a composite comment

To save a composite comment, which you have defined, use the `Add<TExtension>(Comment,TExtension)` method of the `ICommentService`. This method accepts an instance of the `Comment` class and an instance of `TExtension`. It returns an instance of `Composite<Comment,TExtension>`.

Consider the following class, which represents a sample of extension data:

```csharp
public class ReviewExtension {
  public DateTime PurchaseDate {
    get;
    set;
  }
  public string QualityRating {
    get;
    set;
  }
}
```

In the following example, a comment is composed with an instance of this extension class:

```csharp
ICommentService commentService;
DateTime dateOfPurchase;
RatingId ratingOfQuality;

// ...

var parentProduct = Reference.Create("resource://identifier/for/a/resource");
var author = Reference.Create("user://identifier/for/a/user");
var body = "This product is great!";
var isVisible = true;

var comment = new Comment(parentProduct, author, body, isVisible);
var extension = new ReviewExtension
  {
    PurchaseDate = dateOfPurchase,
    QualityRating = ratingOfQuality.Id
  };

var compositeComment = commentService.Add(comment, extension);
```

The previous example invokes the request to add a comment synchronously. Below is an example of adding a comment asynchronously using the asynchronous overload with C#'s async and await keywords.

```csharp
private async Task<Composite<Comment, ReviewExtension>> AddCommentAsync(ICommentService commentService) {
  DateTime dateOfPurchase;
  RatingId ratingOfQuality;

  // ...

  var parentProduct = Reference.Create("resource://identifier/for/a/resource");
  var author = Reference.Create("user://identifier/for/a/user");
  var body = "This product is great!";
  var isVisible = true;

  var comment = new Comment(parentProduct, author, body, isVisible);
  var extension = new ReviewExtension {
    PurchaseDate = dateOfPurchase,
      QualityRating = ratingOfQuality.Id
  };

  var addCommentTask = commentService.AddAsync(comment, extension);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var newComment = await addCommentTask;
  return newComment;
}
```

### Update a composite comment

To update a specific instance of a composite comment, which was added through the platform, use the `Update<TExtension>(Comment,TExtension)` method of the `ICommentService`. Consider the following class, which represents a sample of extension data:

```csharp
public class ReviewExtension
  {
    // ...
  }
```

In the following example, an existing comment is updated with an instance of this extension class:

```csharp
ICommentService commentService;

// ...

// Construct or retrieve an ID for an existing comment.
var idOfExistingComment = CommentId.Create("...");
var parentProduct = Reference.Create("resource://identifier/for/a/resource");
var author = Reference.Create("user://identifier/for/a/user");
var body = "This product is great!";
var isVisible = true;

var comment = new Comment(idOfExistingComment, parentProduct, author, body, isVisible);
var extension = new ReviewExtension
  {
    // ...
  };

commentService.Update(comment, extension);
```

If a comment with the specified ID cannot be found, a `CommentDoesNotExistException` is thrown.

The previous example invokes the request to update a comment synchronously. Below is an example of updating a comment asynchronously using the asynchronous overload with C#'s async and await keywords.

```csharp
private async Task<Composite<Comment, ReviewExtension>> UpdateCommentAsync(ICommentService commentService) {
  // ...

  // Construct or retrieve an ID for an existing comment.
  var idOfExistingComment = CommentId.Create("...");
  var parentProduct = Reference.Create("resource://identifier/for/a/resource");
  var author = Reference.Create("user://identifier/for/a/user");
  var body = "This product is great!";
  var isVisible = true;

  var comment = new Comment(idOfExistingComment, parentProduct, author, body, isVisible);
  var extension = new ReviewExtension {
    // ...
  };

  var updateCommentTask = commentService.UpdateAsync(comment, extension);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var updatedComment = await updatedCommentTask;
  return updatedComment;
}
```

### Retrieve a composite comment

To retrieve a specific instance of a Composite Comment, which was previously added through the platform, use the `Get<TExtension>(CommentId)` method. This method accepts an instance of the `CommentId` class, which identifies the comment to be retrieved. It returns instances of the `Composite<Comment,TExtension>` class corresponding to that identifier.

```csharp
ICommentService commentService;

//...

// Construct a CommentId corresponding to the desired comment
var commentId = CommentId.Create("...");
var compositeComment = commentService.Get<ReviewExtension>(commentId);
```

If a composite comment with the specified ID and extension type cannot be found, a `CommentDoesNotExistException` is thrown.

The previous example invokes the request to retrieve a comment synchronously. An example of retrieving a comment asynchronously using the asynchronous overload with C#'s async and await keywords is described below.

```csharp
private async Task<Composite<Comment, ReviewExtension>> GetCommentAsync(ICommentService commentService) {
  //...

  // Construct a CommentId corresponding to the desired comment
  var commentId = CommentId.Create("...");
  var getCommentTask = commentService.GetAsync<ReviewExtension>(commentId);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var compositeComment = await getCommentTask;
  return compositeComment;
}
```

To retrieve a collection of composite comments, which were previously added through the platform, use the `Get<TExtension>(CompositeCriteria<CommentFilter,TExtension>`) method. This method accepts an instance of `CompositeCriteria<CommentFilter,TExtension>`, which contains the specifications necessary to retrieve the desired comments.

The `Filter` property of the `CompositeCriteria<CommentFilter,TExtension>` class accepts an instance of the `CommentFilter` class. This class contains specifications that let you refine the result set of comments you want to retrieve.

The `ExtensionFilter` property of the `CompositeCriteria<CommentFilter,TExtension>` class accepts a `FilterExpression` that lets you specify a Boolean expression to refine the result set further by values represented within your extension data. (For information on this type of filter, see *Composite Criteria* and *Filtering composites* in [Discover the platform](docId\:NKmGS-fLtRQIYLEWZfb69).

Consider the following class, which represents a sample of extension data:

```csharp
public class ReviewExtension {
  public DateTime PurchaseDate {
    get;
    set;
  }
}
```

In the following example, a page of comments composed with `ReviewExtension` is retrieved, where the value of `PurchaseDate` represents a date after January 1, 2016:

```csharp
ICommentService commentService;

// ...

var criteria = new CompositeCriteria<CommentFilter, ReviewExtension> {
    ExtensionFilter = FilterExpressionBuilder<ReviewExtension> .Field(e => e.PurchaseDate).GreaterThan(new DateTime(2016, 1, 1).ToUniversalTime())
  };

var resultPage = commentService.Get(criteria);
```

In the previous example, the request to retrieve comments is invoked synchronously. An example of retrieving comments asynchronously using the asynchronous overload with C#'s async and await keywords is described below.

```csharp
private async Task<ResultPage<Composite<Comment, ReviewExtension>>> GetCommentsAsync(ICommentService commentService) {
  // ...

  var criteria = new CompositeCriteria<CommentFilter, ReviewExtension> {
      ExtensionFilter = FilterExpressionBuilder<ReviewExtension> .Field(e => e.PurchaseDate).GreaterThan(new DateTime(2016, 1, 1).ToUniversalTime())
    };

  var getCommentsTask = commentService.GetAsync(criteria);

  //Do other application specific work in parallel while the task executes.
  //....

  //Wait until the task runs to completion.
  var pageOfComments = await getCommentTask;
  return pageOfComments;
}
```

Extension data fields may also be applied to sort your result set. The following example demonstrates using an extension data field to define a sorting rule.

```csharp
var criteria = new CompositeCriteria<CommentFilter, ReviewExtension> {
    // ...

    OrderBy = new List<SortInfo> {
      new SortInfo(new SortField(FilterExpressionBuilder<ReviewExtension> .Field(t => t.PurchaseDate)), true),
    }
  };
```
