예제 #1
0
        /// <summary>
        /// Delete the provided objects from the table.
        /// </summary>
        /// <typeparam name="T">Type of business object</typeparam>
        /// <param name="objects">Collection of objects</param>
        public ulong DeleteList <T>(IEnumerable <T> objects)
            where T : class
        {
            if (objects != null)
            {
                // we need to check if we are soft-deleting!
                ClassInformation?objectInfo = TypeInspector.InspectForAzureTables <T>();
                if (objectInfo == null)
                {
                    throw new TypeLoadException($"Type '{typeof(T).FullName}' is not anotated with the '{typeof(TableAttribute).FullName}' attribute.");
                }

                if (objectInfo.TableAttribute.UseSoftDelete)
                {
                    return(UpdateInternal(objects, true));
                }

                TableBatchOperation delete = new TableBatchOperation();
                foreach (T instance in objects)
                {
                    delete.Delete(AzureTableEntity.From(instance, true));
                }

                ulong count = (ulong)delete.Count;
                if (count > 0)
                {
                    ExecuteNonQuery <T>(delete);
                    return(count);
                }
            }

            return(0L);
        }
예제 #2
0
        /// <summary>
        /// Delete the provided object from the table
        /// </summary>
        /// <typeparam name="T">Type of business object</typeparam>
        /// <param name="item">Business object</param>
        /// <returns>Zero if nothing was deleted, One if the object was deleted</returns>
        public ulong Delete <T>(T item)
            where T : class
        {
            if (item != null)
            {
                // we need to check if we are soft-deleting!
                ClassInformation?objectInfo = TypeInspector.InspectForAzureTables <T>();
                if (objectInfo == null)
                {
                    throw new TypeLoadException($"Type '{typeof(T).FullName}' is not anotated with the '{typeof(TableAttribute).FullName}' attribute.");
                }

                TableAttribute   tableAttribute = objectInfo.TableAttribute;
                AzureTableEntity entity         = AzureTableEntity.From(item);
                TableOperation   updateOrDeleteOperation;

                if (tableAttribute.UseSoftDelete)
                {
                    entity.AddOrUpdateProperty(AzureTableEntity.PROPERTY_NAME_ISDELETED, true);
                    updateOrDeleteOperation = TableOperation.Merge(entity);
                }
                else
                {
                    updateOrDeleteOperation = TableOperation.Delete(entity);
                }

                ExecuteNonQuery <T>(updateOrDeleteOperation);
                return(1L);
            }

            return(0L);
        }
예제 #3
0
        /// <summary>
        /// Performs the actual UPDATE operation
        /// </summary>
        /// <typeparam name="T">Type of business object</typeparam>
        /// <param name="objects">Collection of objects</param>
        /// <param name="setSoftDeleteFlag">If TRUE, then we update the IsDeleted flag</param>
        private ulong UpdateInternal <T>(IEnumerable <T> objects, bool setSoftDeleteFlag = false)
            where T : class
        {
            if (objects != null)
            {
                TableBatchOperation update = new TableBatchOperation();
                foreach (T instance in objects)
                {
                    AzureTableEntity entity = AzureTableEntity.From(instance);
                    if (setSoftDeleteFlag)
                    {
                        entity.AddOrUpdateProperty(AzureTableEntity.PROPERTY_NAME_ISDELETED, true);
                    }
                    update.Merge(entity);
                }

                ulong count = (ulong)update.Count;
                if (count > 0)
                {
                    ExecuteNonQuery <T>(update);
                    return(count);
                }
            }

            return(0L);
        }
        /// <summary>
        /// Queue a new operation
        /// </summary>
        /// <typeparam name="T">Type of businessObject</typeparam>
        /// <param name="businessObject">Business object instance - cannot be NULL.</param>
        /// <param name="type">Type of TableOperation to generate</param>
        public void Add <T>(T businessObject, TableOperationType type) where T : class
        {
            if (_isDraining)
            {
                // no items can be added during a drain
                throw new Exception("Cannot queue items during a drain.");
            }

            if (businessObject == null)
            {
                throw new ArgumentNullException("businessObject");
            }

            TableOperation operation = type switch
            {
                TableOperationType.Delete => TableOperation.Delete(AzureTableEntity.From(businessObject, forDelete: true)),
                TableOperationType.Insert => TableOperation.Insert(AzureTableEntity.From(businessObject)),
                TableOperationType.InsertOrMerge => TableOperation.InsertOrMerge(AzureTableEntity.From(businessObject)),
                TableOperationType.InsertOrReplace => TableOperation.InsertOrReplace(AzureTableEntity.From(businessObject)),
                TableOperationType.Merge => TableOperation.Merge(AzureTableEntity.From(businessObject)),
                TableOperationType.Replace => TableOperation.Replace(AzureTableEntity.From(businessObject)),
                _ => throw new ArgumentOutOfRangeException("Unsupported operation for queue!")
            };

            _queueOrder.Enqueue(_queueIndex);

            _queue.TryAdd(_queueIndex++, new TableOperationWrapper(operation, AzureTablesDataSource.GetTableName <T>()));
        }
예제 #5
0
        public ulong Update <T>(T item)
            where T : class
        {
            if (item != null)
            {
                ExecuteNonQuery <T>(TableOperation.Merge(AzureTableEntity.From(item)));
                return(1L);
            }

            return(0L);
        }
예제 #6
0
        /// <summary>
        /// Replace an entity with a new one. Especially useful when row/partition keys are being
        /// modified or when the table row can contain columns not present in its entity representation (slice-tables)
        /// </summary>
        /// <typeparam name="T">Type of business object</typeparam>
        /// <param name="newCopy">The new data</param>
        /// <param name="originalPartitionKey">The partition key for the original object</param>
        /// <param name="originalRowKey">The row key for the original object</param>
        public void ReplaceWith <T>(T newCopy, string?originalPartitionKey = null, string?originalRowKey = null)
            where T : class
        {
            if ((newCopy == null) || (string.IsNullOrWhiteSpace(originalPartitionKey) && string.IsNullOrWhiteSpace(originalRowKey)))
            {
                throw new ArgumentNullException();
            }

            StringBuilder query = new StringBuilder();

            if (UsesIsDeleted)
            {
                query.Append("(IsDeleted eq false)");
            }

            if (!string.IsNullOrWhiteSpace(originalPartitionKey))
            {
                query.Append($" and (PartitionKey eq '{originalPartitionKey}')");
            }

            if (!string.IsNullOrWhiteSpace(originalRowKey))
            {
                query.Append($" and (RowKey eq '{originalRowKey}')");
            }

            TableQuery <AzureTableEntity> tableQuery = (new TableQuery <AzureTableEntity>()).Where(query.ToString());
            AzureTableEntity?originalEntity          = _currentTableReference.ExecuteQuery(tableQuery).FirstOrDefault();

            if ((originalEntity == default) || (originalRowKey == default))
            {
                Insert(new T[] { newCopy });
                return;
            }

            TableOperation delete = TableOperation.Delete(originalEntity);

            ExecuteNonQuery <T>(delete);

            originalEntity.ImportValues(AzureTableEntity.From(newCopy));
            TableOperation insert = TableOperation.Insert(originalEntity);

            ExecuteNonQuery <T>(insert);
        }
예제 #7
0
        /// <summary>
        /// Inserts the provided objects into the table.
        /// </summary>
        /// <typeparam name="T">Type of business object</typeparam>
        /// <param name="objects">Collection of objects</param>
        public ulong InsertList <T>(IEnumerable <T> objects)
            where T : class
        {
            if (objects != null)
            {
                TableBatchOperation insert = new TableBatchOperation();
                foreach (T instance in objects)
                {
                    insert.Insert(AzureTableEntity.From(instance));
                }

                ulong count = (ulong)insert.Count;
                if (count > 0)
                {
                    ExecuteNonQuery <T>(insert);
                    return(count);
                }
            }

            return(0L);
        }
예제 #8
0
        /// <summary>
        /// Queue a new operation
        /// </summary>
        /// <typeparam name="T">Type of businessObject</typeparam>
        /// <param name="listOfObjects">Business object instances - cannot be NULL.</param>
        /// <param name="type">Type of TableBatchOperation to generate</param>
        public void Add <T>(IEnumerable <T> listOfObjects, TableOperationType type) where T : class
        {
            if (_isDraining)
            {
                // no items can be added during a drain
                throw new Exception("Cannot queue items during a drain.");
            }

            if (listOfObjects == null)
            {
                throw new ArgumentNullException(nameof(listOfObjects));
            }

            int t = (int)type;

            // these are the int values of the range of operation types supported
            if ((t < 0) || (t > 5))
            {
                throw new ArgumentOutOfRangeException("Unsupported operation for queue!");
            }

            string currentPartitionKey = Guid.NewGuid().ToString(); // nobody's partition key will ever be the same as this!
            string tableName           = AzureTablesDataSource.GetTableName <T>();
            string operationName       = Enum.GetName(typeof(TableOperationType), type) ?? "Unknown";

            TableBatchOperation batch = new TableBatchOperation();

            foreach (T obj in listOfObjects)
            {
                TableOperation tableOperation = type switch
                {
                    TableOperationType.Delete => TableOperation.Delete(AzureTableEntity.From(obj, forDelete: true)),
                    TableOperationType.Insert => TableOperation.Insert(AzureTableEntity.From(obj)),
                    TableOperationType.InsertOrMerge => TableOperation.InsertOrMerge(AzureTableEntity.From(obj)),
                    TableOperationType.InsertOrReplace => TableOperation.InsertOrReplace(AzureTableEntity.From(obj)),
                    TableOperationType.Merge => TableOperation.Merge(AzureTableEntity.From(obj)),
                    TableOperationType.Replace => TableOperation.Replace(AzureTableEntity.From(obj))

                    // Actually redundant, since this is already checked at the top of the function.
                    ,
                    _ => throw new ArgumentOutOfRangeException($"Unsupported operation '{operationName}'")
                };

                // all items in a batch must be the same partition key
                // so if we hit a different one, we jump to a new batch
                if ((batch.Count > 0) && (tableOperation.Entity.PartitionKey != currentPartitionKey))
                {
                    _queue.Enqueue(new TableBatchOperationWrapper(batch, tableName));

                    batch = new TableBatchOperation();
                    currentPartitionKey = tableOperation.Entity.PartitionKey;
                }
                else if (batch.Count == 0)
                {
                    currentPartitionKey = tableOperation.Entity.PartitionKey;
                }

                batch.Add(tableOperation);

                if (batch.Count == __MAX_ITEMS_PER_BATCH)
                {
                    _queue.Enqueue(new TableBatchOperationWrapper(batch, tableName));

                    batch = new TableBatchOperation();
                }

                ItemAdded?.Invoke(tableName, operationName, currentPartitionKey, tableOperation.Entity.RowKey);
            }

            // flush remaining entities to the queue
            if (batch.Count > 0)
            {
                _queue.Enqueue(new TableBatchOperationWrapper(batch, tableName));
            }
        }