예제 #1
0
        /// <summary>
        /// Execute a CRUD operation
        /// </summary>
        /// <param name="operation">The operation to execute (as Azure TableBatchOperation)</param>
        public async void ExecuteNonQuery(TableBatchOperation operation)
        {
            // TBOs must be paged by partition key, and no more than a 100 items per batch page
            if (operation.Count > 0)
            {
                TableBatchOperation batchPage = new();

                // all entities in a batch must have the same partition key:
                foreach (IEnumerable <TableOperation> operations in operation.GroupBy(o => o.Entity.PartitionKey))
                {
                    // order elements in a partition by row key so that we reduce tablescans
                    foreach (TableOperation op in operations.OrderBy(o => o.Entity.RowKey))
                    {
                        batchPage.Add(op);
                        if (batchPage.Count == 100)
                        {
                            await Connection.ExecuteBatchAsync(batchPage);

                            batchPage.Clear();
                        }
                    }
                }

                // get the remaining
                if (batchPage.Count > 0)
                {
                    await Connection.ExecuteBatchAsync(batchPage);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Execute a DML operation
        /// </summary>
        /// <typeparam name="T">Class type of the business object</typeparam>
        /// <param name="batchOperation">TableBatchOperation to execute</param>
        public void ExecuteNonQuery <T>(TableBatchOperation batchOperation)
            where T : class
        {
            if (batchOperation.Count > 0)
            {
                TableBatchOperation batchPage = new TableBatchOperation();

                // all entities in a batch must have the same partition key:
                foreach (IEnumerable <TableOperation> operations in batchOperation.GroupBy(o => o.Entity.PartitionKey))
                {
                    // order elements in a partition by row key so that we reduce tablescans
                    foreach (TableOperation operation in operations.OrderBy(o => o.Entity.RowKey))
                    {
                        batchPage.Add(operation);
                        if (batchPage.Count == 100)
                        {
                            _currentTableReference.ExecuteBatch(batchPage);
                            batchPage.Clear();
                        }
                    }
                }

                // get the remaining
                if (batchPage.Count > 0)
                {
                    _currentTableReference.ExecuteBatch(batchPage);
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Queue a new operation
        /// </summary>
        /// <param name="batch">TableBatchOperation to queue</param>
        /// <param name="tableName">Name of the table to run it against</param>
        public void Add(TableBatchOperation batch, string tableName)
        {
            if (_isDraining)
            {
                // no items can be added during a drain
                throw new Exception("Cannot queue items during a drain.");
            }

            if ((batch == null) || (batch.Count == 0))
            {
                throw new ArgumentNullException("Empty batch");
            }

            if (string.IsNullOrWhiteSpace(tableName))
            {
                throw new ArgumentNullException("tableName");
            }

            // examine the batch, split into unique operations of a max of 100 elements each
            foreach (IGrouping <string, TableOperation> operationByPartitionKeys in batch.GroupBy(b => b.Entity.PartitionKey))
            {
                string partitionKey = operationByPartitionKeys.Key;

                Dictionary <TableOperationType, TableBatchOperationWrapper> operationsByType = new Dictionary <TableOperationType, TableBatchOperationWrapper>()
                {
                    { TableOperationType.Delete, new TableBatchOperationWrapper(new TableBatchOperation(), tableName) },
                    { TableOperationType.Insert, new TableBatchOperationWrapper(new TableBatchOperation(), tableName) },
                    { TableOperationType.InsertOrMerge, new TableBatchOperationWrapper(new TableBatchOperation(), tableName) },
                    { TableOperationType.InsertOrReplace, new TableBatchOperationWrapper(new TableBatchOperation(), tableName) },
                    { TableOperationType.Merge, new TableBatchOperationWrapper(new TableBatchOperation(), tableName) },
                    { TableOperationType.Replace, new TableBatchOperationWrapper(new TableBatchOperation(), tableName) }
                };

                foreach (TableOperation operation in operationByPartitionKeys.OrderBy(o => o.Entity.RowKey).ThenBy(o => o.OperationType))
                {
                    if ((operation.OperationType == TableOperationType.Invalid) || (operation.OperationType == TableOperationType.Retrieve))
                    {
                        throw new ArgumentOutOfRangeException("Unsupported operation for queue!");
                    }

                    operationsByType[operation.OperationType].Batch.Add(operation);
                    ItemAdded?.Invoke(tableName, Enum.GetName(typeof(TableOperationType), operation.OperationType) ?? "Unknown", partitionKey, operation.Entity.RowKey);

                    if (operationsByType[operation.OperationType].Batch.Count == 100)
                    {
                        _queue.Enqueue(operationsByType[operation.OperationType]);
                        operationsByType[operation.OperationType] = new TableBatchOperationWrapper(new TableBatchOperation(), tableName);
                    }
                }

                // flush each op/group to the queue, because next iteration of the loop changes the partition key
                foreach (TableOperationType type in operationsByType.Keys)
                {
                    if (operationsByType[type].Batch.Count > 0)
                    {
                        _queue.Enqueue(operationsByType[type]);
                    }
                }
            }
        }