Area: Optimizely Commerce
Applies to versions: 12.6 and higher

Searching for orders using abstractions

Recommended reading 

This topic describes how to work with order search functionality using abstractions in Optimizely Commerce.

How it works

IOrderSearchService, available in the EPiServer.Commerce.Order namespace, retrieves historical data for IOrderGroup. You can for example search for IOrderGroup (ICart, IPurchaseOrder, IPaymentPlan), apply filters, and modify search results.

 /// <summary>
 /// Finds orders with a specific <see cref="OrderSearchFilter"/> for a specific <typeparamref name="TOrderGroup"/>.
 /// </summary>
 /// <typeparam name="TOrderGroup">The given order type for filter.</typeparam>
 /// <param name="filter">The search filter.</param>
 /// <returns>The order search results.</returns>
        OrderSearchResults Find(OrderSearchFilter filter) where TOrderGroup : class, IOrderGroup;

This API finds orders with a specific OrderSearchFilter for a specific TOrderGroup, then returns OrderSearchResults.

Filtering orders in search

OrderSearchFilter has a criteria set for filtering orders in the search results.

  • CreatedFrom. Specifies the time that returned orders were created after.
  • CreatedTo. Specifies the time that returned orders were created before.
  • MarketId. Specifies that only orders created in identified markets should be returned.
  • ModifiedFrom. Specifies the time that returned orders were modified after.
  • ModifiedTo. Specifies the time that returned orders were modified before.
  • StartingIndex. Gets or sets the starting index.
  • RecordsToRetrieve. Gets or sets the number of records to retrieve.

Note: The search is inclusive; begin and end values are included for datetime filters (CreatedFrom, CreatedTo, ModifiedFrom, ModifiedTo).

Search results for orders

OrderSearchResults contains a collection of orders found IEnumerable <T> Orders and the number of records found int TotalRecords.

As with other abstraction APIs, you can modify this API using a custom implementation.

using EPiServer.Framework;
using EPiServer.ServiceLocation;
using Mediachase.Commerce.Orders;
using Mediachase.Commerce.Orders.Search;
using Mediachase.MetaDataPlus.Extensions;
using System;
using System.Linq;

namespace EPiServer.Commerce.Order.Internal
    /// <summary>
    /// This class is intended to be used internally by EPiServer.
    /// We do not support any backward compatibility on this.
    /// Default implementation of .
    /// </summary>
    [ServiceConfiguration(ServiceType = typeof(IOrderSearchService), Lifecycle = ServiceInstanceScope.Singleton)]
    public class DefaultOrderSearchService : IOrderSearchService
        private readonly ICartSearchService _cartSearch;

        public DefaultOrderSearchService(ICartSearchService cartSearch)
            Validator.ThrowIfNull(nameof(cartSearch), cartSearch);
            _cartSearch = cartSearch;

        public virtual OrderSearchResults Find(OrderSearchFilter filter) where TOrderGroup : class, IOrderGroup
            Validator.ThrowIfNull(nameof(filter), filter);
            var type = typeof(TOrderGroup);
            if (IsCart(type))
                var carts = _cartSearch.FindCarts(filter.CreatedFrom, filter.CreatedTo,
                            filter.MarketId, filter.StartingIndex ?? 0,
                            filter.RecordsToRetrieve ?? int.MaxValue,
                            out int totalRecords).OfType();
                return new OrderSearchResults(carts, totalRecords);

            string sqlMetaWhereClause = $@"(META.Created BETWEEN '{(filter.CreatedFrom ?? DateTime.MinValue.TruncateToSqlDateTimeRange()).ToString("s")}' 
                                                             AND '{(filter.CreatedTo ?? DateTime.MaxValue.TruncateToSqlDateTimeRange()).ToString("s")}')";

            sqlMetaWhereClause += $@" AND (META.Modified BETWEEN '{(filter.ModifiedFrom ?? DateTime.MinValue.TruncateToSqlDateTimeRange()).ToString("s")}' 
                                                             AND '{(filter.ModifiedTo ?? DateTime.MaxValue.TruncateToSqlDateTimeRange()).ToString("s")}')";

            var parameters = new OrderSearchParameters() { SqlMetaWhereClause = sqlMetaWhereClause};

            if (!string.IsNullOrEmpty(filter.MarketId))
                parameters.SqlWhereClause = $"MarketId = '{filter.MarketId}'";

            var options = new OrderSearchOptions
                StartingRecord = filter.StartingIndex ?? 0,
                RecordsToRetrieve = filter.RecordsToRetrieve ?? int.MaxValue

            if (IsPurchaseOrder(type))
                var orders = OrderContext.Current.FindPurchaseOrders(parameters, options, out int totalRecords).OfType();
                return new OrderSearchResults(orders, totalRecords);

            if (IsPaymentPlan(type))
                var paymentplans = OrderContext.Current.FindPaymentPlans(parameters, options, out int totalRecords).OfType();
                return new OrderSearchResults(paymentplans, totalRecords);

            throw new InvalidOperationException($"The type {typeof(TOrderGroup)} is not supported.");

        private static bool IsCart(Type type)
            return typeof(ICart).IsAssignableFrom(type);

        private static bool IsPurchaseOrder(Type type)
            return typeof(IPurchaseOrder).IsAssignableFrom(type);

        private static bool IsPaymentPlan(Type type)
            return typeof(IPaymentPlan).IsAssignableFrom(type);

Extension methods

You can also use IOrderSearchServiceExtensions to provide convenient extension methods when working with IOrderSearchService.

  • FindCarts
  • FindPurchaseOrders
  • FindPaymentPlans
var orderFilter = new OrderSearchFilter
    CreatedFrom = DateTime.UtcNow.AddDays(-365),
    CreatedTo = DateTime.UtcNow
var orderSearchService = ServiceLocator.Current.GetInstance<IOrderSearchService>()
var searchResult = orderSearchService.FindPurchaseOrders(orderFilter);
var orders = searchResult.Orders;
var totalRecords = searchResult.TotalRecords;
Do you find this information helpful? Please log in to provide feedback.

Last updated: Oct 27, 2020

Recommended reading