/// <summary>
        /// Processes the specified commerce context.
        /// </summary>
        /// <param name="commerceContext">The commerce context.</param>
        /// <returns>User site terms</returns>
        public virtual async Task <IEnumerable <Customer> > Process(CommerceContext commerceContext)
        {
            using (CommandActivity.Start(commerceContext, this))
            {
                var sqlContext = ConnectionHelper.GetProfilesSqlContext(commerceContext);
                var rows       = await sqlContext.GetAllProfiles();

                var migratedCustomers = new List <Customer>();

                foreach (DataRow row in rows)
                {
                    try
                    {
                        var contextOptions = commerceContext.GetPipelineContextOptions();

                        var csCustomer = await this._migrateCustomerPipeline.Run(row, contextOptions);

                        if (csCustomer != null)
                        {
                            migratedCustomers.Add(csCustomer);
                        }
                    }
                    catch (Exception ex)
                    {
                        await commerceContext.AddMessage(
                            commerceContext.GetPolicy <KnownResultCodes>().Error,
                            "EntityNotFound",
                            new object[] { row["u_user_id"] as string, ex },
                            $"Customer {row["u_user_id"] as string} was not migrated.");
                    }
                }

                return(migratedCustomers);
            }
        }
        /// <summary>
        /// The execute.
        /// </summary>
        /// <param name="arg">The argument.</param>
        /// <param name="context">The context.</param>
        /// <returns>
        /// The collection of profile definitions <see cref="ProfileDefinition" />.
        /// </returns>
        public override async Task <IEnumerable <ProfileDefinition> > Run(string arg, CommercePipelineExecutionContext context)
        {
            var    cachePolicy = context.GetPolicy <ProfilesCsCachePolicy>();
            var    cacheKey    = string.IsNullOrEmpty(arg) ? "ProfileDefinition.All" : $"{arg}";
            ICache cache       = null;

            if (cachePolicy.AllowCaching)
            {
                cache = await this._cachePipeline.Run(new EnvironmentCacheArgument { CacheName = cachePolicy.CacheName }, context);

                var item = await cache.Get(cacheKey) as List <ProfileDefinition>;

                if (item != null)
                {
                    return(item);
                }
            }

            try
            {
                var schema     = new List <ProfileDefinition>();
                var sqlContext = ConnectionHelper.GetProfilesSqlContext(context.CommerceContext);
                if (string.IsNullOrEmpty(arg))
                {
                    schema = await sqlContext.GetAllProfileDefinitions();

                    if (schema != null && schema.Count > 0)
                    {
                        if (cachePolicy.AllowCaching && cache != null)
                        {
                            await cache.Set(cacheKey, new Cachable <List <ProfileDefinition> >(schema, 1), cachePolicy.GetCacheEntryOptions());
                        }

                        context.CommerceContext.AddUniqueObjectByType(schema);
                        return(schema);
                    }
                }
                else
                {
                    var profileDefinition = await sqlContext.GetProfileDefinition(arg);

                    if (profileDefinition != null)
                    {
                        schema.Add(profileDefinition);
                        if (cachePolicy.AllowCaching && cache != null)
                        {
                            await cache.Set(cacheKey, new Cachable <List <ProfileDefinition> >(schema, 1), cachePolicy.GetCacheEntryOptions());
                        }

                        return(schema);
                    }
                }

                await context.CommerceContext.AddMessage(
                    context.GetPolicy <KnownResultCodes>().Error,
                    "EntityNotFound",
                    new object[] { arg },
                    $"Entity {arg} was not found.");

                return(null);
            }
            catch (Exception ex)
            {
                await context.CommerceContext.AddMessage(
                    context.GetPolicy <KnownResultCodes>().Error,
                    "EntityNotFound",
                    new object[] { arg, ex },
                    $"Entity {arg} was not found.");

                return(null);
            }
        }
        /// <summary>
        /// Addresses the component generator.
        /// </summary>
        /// <param name="addressId">The address identifier.</param>
        /// <param name="profileDefinition">The profile definition.</param>
        /// <param name="context">The context.</param>
        /// <returns>
        /// A <see cref="AddressComponent" />
        /// </returns>
        internal static async Task <AddressComponent> AddressComponentGenerator(string addressId, ProfileDefinition profileDefinition, CommercePipelineExecutionContext context)
        {
            // map properties to AddressComponent
            var addressType      = context.GetPolicy <ProfilePropertiesPolicy>().AddressType;
            var addressComponent = new AddressComponent {
                Name = addressType
            };

            try
            {
                var sqlContext = ConnectionHelper.GetProfilesSqlContext(context.CommerceContext);
                var address    = await sqlContext.GetAddress(addressId).ConfigureAwait(false);

                addressComponent.Id = addressId;

                var addressProperties = context.GetPolicy <ProfilePropertiesMappingPolicy>().AddressProperties;
                var details           = new EntityView {
                    Name = "Details"
                };

                foreach (var property in profileDefinition.Properties)
                {
                    if (addressProperties.ContainsKey($"{property.GroupName}.{property.Name}"))
                    {
                        var rawValue = address[property.ColumnName] as string;
                        if (string.IsNullOrEmpty(rawValue) || property.Name.Equals("address_id", StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        var addressProperty = addressProperties[$"{property.GroupName}.{property.Name}"];
                        var propertyInfo    = addressComponent.Party.GetType().GetProperty(addressProperty, BindingFlags.Public | BindingFlags.Instance);
                        if (propertyInfo != null && propertyInfo.CanWrite)
                        {
                            propertyInfo.SetValue(addressComponent.Party, rawValue, null);
                        }
                        else
                        {
                            TypeConverter typeConverter = TypeDescriptor.GetConverter(property.OriginalType);
                            var           profileValue  = typeConverter.ConvertFromString(rawValue);
                            details.Properties.Add(new ViewProperty {
                                Name = addressProperty, RawValue = profileValue
                            });
                        }
                    }
                }

                if (details.Properties.Any())
                {
                    addressComponent.View.ChildViews.Add(details);
                }
            }
            catch (Exception ex)
            {
                await context.CommerceContext.AddMessage(
                    context.GetPolicy <KnownResultCodes>().Error,
                    "EntityNotFound",
                    new object[] { addressId, ex },
                    $"Address { addressId } was not found.").ConfigureAwait(false);

                return(null);
            }

            return(addressComponent);
        }