private async Task ValidateTableEntityAgainstIndexDefinitionsAsync(TableEntityWrapper <TDomainEntity> tableEntityWrapper)
        {
            foreach (var indexDefinition in IndexDefinitions)
            {
                if (!indexDefinition.DomainObjectMatchesIndexCriteria(tableEntityWrapper.DomainObjectInstance))
                {
                    continue;
                }
                var tempTableEntity = new TableEntityWrapper <TDomainEntity>(domainObject: tableEntityWrapper.DomainObjectInstance)
                {
                    PartitionKey = indexDefinition.IndexNameKey
                };

                // Checks if the current partition key has been registered with the list of partition keys for the table
                if (_partitionMetaDataEntityWrapper.DomainObjectInstance.PartitionKeys.All(schemaPartitionKey => schemaPartitionKey != tempTableEntity.PartitionKey))
                {
                    _partitionMetaDataEntityWrapper.DomainObjectInstance.PartitionKeys.Add(tempTableEntity.PartitionKey);
                    await SaveIndexNameKeysAsync().ConfigureAwait(false);
                }
                tempTableEntity.RowKey = indexDefinition.GetRowKeyFromCriteria(tempTableEntity.DomainObjectInstance);

                // Need to get the Object that is to be indexed and then wrap it in a reference object for proper JSV serialization.
                var indexedPropertyObject = indexDefinition.GetIndexedPropertyFromCriteria(tempTableEntity.DomainObjectInstance);
                tempTableEntity.IndexedProperty = new IndexedObject
                {
                    ValueBeingIndexed = indexedPropertyObject
                };
                indexDefinition.CloudTableEntities.Add(tempTableEntity);
            }
        }
        private void LoadTableMetaData()
        {
            // Try to load the partition meta data from the existing table (which contains a list of the partition keys in the table).
            _partitionMetaDataEntityWrapper = _tableMetaDataContext.Find(CtConstants.TableMetaDataPartitionKey, CtConstants.PartitionSchemasRowKey);

            // Set the default PartitionKey using the combination below in case there are more than one CloudTableContext objects
            // on the same table.
            _defaultIndexDefinitionName = $"DefaultIndex_ofType_{typeof(TDomainEntity).Name}";
            if (_partitionMetaDataEntityWrapper != null)
            {
                /* This is going through and populating the local PartitionKeysInTable property with the list of keys retrieved
                 * from the Azure table.
                 * This also checks to see if there is a PartitionKey for the table meta data and the DefaultPartition
                 * and adds that if there isn't*/
                var metaDataPkIsInList = false;
                foreach (var partitionKeyString in _partitionMetaDataEntityWrapper.DomainObjectInstance.PartitionKeys)
                {
                    if (partitionKeyString == CtConstants.TableMetaDataPartitionKey)
                    {
                        metaDataPkIsInList = true;
                    }
                    var isInList = false;
                    foreach (var item in IndexNameKeysInTable)
                    {
                        if (item == partitionKeyString)
                        {
                            isInList = true;
                        }
                    }
                    if (!isInList)
                    {
                        IndexNameKeysInTable.Add(partitionKeyString);
                    }
                }
                if (!metaDataPkIsInList)
                {
                    IndexNameKeysInTable.Add(CtConstants.TableMetaDataPartitionKey);
                }

                // The RowKey for the DefaultSchema is set by the given ID property of the TDomainEntity object
                DefaultIndex = CreateIndexDefinition(_defaultIndexDefinitionName)
                               .DefineIndexCriteria(entity => true)
                               .SetIndexedPropertyCriteria(entity => entity.GetType().Name); // Enables searching directly on the type.
                if (IndexDefinitions.All(indexDefinition => indexDefinition.IndexNameKey != DefaultIndex.IndexNameKey))
                {
                    AddIndexDefinition(DefaultIndex);
                }
            }
            else
            {
                /* Creates a new partition meta data entity and adds the appropriate default partitions and metadata partitions*/
                _partitionMetaDataEntityWrapper = new TableEntityWrapper <PartitionMetaData>(CtConstants.TableMetaDataPartitionKey,
                                                                                             CtConstants.PartitionSchemasRowKey);
                DefaultIndex = CreateIndexDefinition(_defaultIndexDefinitionName)
                               .DefineIndexCriteria(entity => true)
                               .SetIndexedPropertyCriteria(entity => entity.GetType().Name); // Enables searching directly on the type
                AddIndexDefinition(DefaultIndex);
            }
        }
        private void ExecuteTableOperation(TDomainEntity domainEntity, SaveType batchOperation)
        {
            VerifyAllIndexDefinitionsExist();
            RunTableIndexing();
            var tempTableEntity = new TableEntityWrapper <TDomainEntity>
            {
                DomainObjectInstance = domainEntity
            };

            ValidateTableEntityAgainstIndexDefinitions(tempTableEntity);
            WriteIndexDefinitionsToTable(batchOperation);
        }
        private async Task ExecuteTableOperationAsync(TDomainEntity domainEntity, SaveType batchOperation)
        {
            await VerifyAllPartitionsExistAsync().ConfigureAwait(false);
            await RunTableIndexingAsync().ConfigureAwait(false);

            var tempTableEntity = new TableEntityWrapper <TDomainEntity>
            {
                DomainObjectInstance = domainEntity
            };

            await ValidateTableEntityAgainstIndexDefinitionsAsync(tempTableEntity).ConfigureAwait(false);
            await WriteIndexDefinitionsToTableAsync(batchOperation).ConfigureAwait(false);
        }
        /// <summary>
        /// Asynchronously gets a set of domain entities based on a given index definition with a filter based on the value object (indexedProperty) that gets passed in.
        /// </summary>
        /// <param name="indexDefinitionName">Index definition name</param>
        /// <param name="indexedProperty"></param>
        /// <returns></returns>
        public async Task <List <TDomainEntity> > GetByIndexedPropertyAsync(string indexDefinitionName, object indexedProperty)
        {
            var tempCloudTableEntity = new TableEntityWrapper <TDomainEntity>
            {
                IndexedProperty =
                {
                    ValueBeingIndexed = indexedProperty
                }
            };
            var serializedIndexedProperty = JsonConvert.SerializeObject(tempCloudTableEntity.IndexedProperty);
            var entities = await TableOperationsService.QueryWherePropertyEqualsAsync(indexDefinitionName, CtConstants.PropNameIndexedProperty, serializedIndexedProperty).ConfigureAwait(false);

            return(entities.Select(cte => cte.DomainObjectInstance).ToList());
        }
        /// <summary>
        /// Gets a set of domain entities based on a given indexNameKey with a filter based on the indexProperty that gets passed in.
        /// </summary>
        /// <param name="indexNameKey">Name of the index</param>
        /// <param name="indexedProperty">Value to be searching for inside the index</param>
        /// <returns></returns>
        public IEnumerable <TDomainEntity> GetByIndexedProperty(string indexNameKey, object indexedProperty)
        {
            var tempCloudTableEntity = new TableEntityWrapper <TDomainEntity>
            {
                IndexedProperty =
                {
                    ValueBeingIndexed = indexedProperty
                }
            };
            var serializedIndexedProperty = JsonConvert.SerializeObject(tempCloudTableEntity.IndexedProperty);

            return(TableOperationsService.QueryWherePropertyEquals(indexNameKey, CtConstants.PropNameIndexedProperty, serializedIndexedProperty)
                   .Select(cloudTableEntity => cloudTableEntity.DomainObjectInstance));
        }
 private void ExecuteTableOperation(IEnumerable <TDomainEntity> domainEntities, SaveType batchOperation)
 {
     VerifyAllIndexDefinitionsExist();
     RunTableIndexing();
     foreach (var domainEntity in domainEntities)
     {
         var tempTableEntity = new TableEntityWrapper <TDomainEntity>
         {
             DomainObjectInstance = domainEntity
         };
         ValidateTableEntityAgainstIndexDefinitions(tempTableEntity);
     }
     WriteIndexDefinitionsToTable(batchOperation);
 }