/// <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); }
/// <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); }
/// <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>())); }
public ulong Update <T>(T item) where T : class { if (item != null) { ExecuteNonQuery <T>(TableOperation.Merge(AzureTableEntity.From(item))); return(1L); } return(0L); }
/// <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); }
/// <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); }
/// <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)); } }