public async Task BatchItemETagAsync()
        {
            Container container = BatchTestBase.JsonContainer;

            await this.CreateJsonTestDocsAsync(container);

            {
                TestDoc testDocToCreate = BatchTestBase.PopulateTestDoc(this.PartitionKey1);

                TestDoc testDocToReplace = this.GetTestDocCopy(this.TestDocPk1ExistingA);
                testDocToReplace.Cost++;

                ItemResponse <TestDoc> readResponse = await BatchTestBase.JsonContainer.ReadItemAsync <TestDoc>(
                    this.TestDocPk1ExistingA.Id,
                    BatchTestBase.GetPartitionKey(this.PartitionKey1));

                TransactionalBatchItemRequestOptions firstReplaceOptions = new TransactionalBatchItemRequestOptions()
                {
                    IfMatchEtag = readResponse.ETag
                };

                TransactionalBatchResponse batchResponse = await new BatchCore((ContainerCore)container, BatchTestBase.GetPartitionKey(this.PartitionKey1))
                                                           .CreateItem(testDocToCreate)
                                                           .ReplaceItem(testDocToReplace.Id, testDocToReplace, requestOptions: firstReplaceOptions)
                                                           .ExecuteAsync();

                BatchSinglePartitionKeyTests.VerifyBatchProcessed(batchResponse, numberOfOperations: 2);

                Assert.AreEqual(HttpStatusCode.Created, batchResponse[0].StatusCode);
                Assert.AreEqual(HttpStatusCode.OK, batchResponse[1].StatusCode);

                await BatchTestBase.VerifyByReadAsync(container, testDocToCreate, eTag : batchResponse[0].ETag);

                await BatchTestBase.VerifyByReadAsync(container, testDocToReplace, eTag : batchResponse[1].ETag);
            }

            {
                TestDoc testDocToReplace = this.GetTestDocCopy(this.TestDocPk1ExistingB);
                testDocToReplace.Cost++;

                TransactionalBatchItemRequestOptions replaceOptions = new TransactionalBatchItemRequestOptions()
                {
                    IfMatchEtag = BatchTestBase.Random.Next().ToString()
                };

                TransactionalBatchResponse batchResponse = await new BatchCore((ContainerCore)container, BatchTestBase.GetPartitionKey(this.PartitionKey1))
                                                           .ReplaceItem(testDocToReplace.Id, testDocToReplace, requestOptions: replaceOptions)
                                                           .ExecuteAsync();

                BatchSinglePartitionKeyTests.VerifyBatchProcessed(
                    batchResponse,
                    numberOfOperations: 1,
                    expectedStatusCode: HttpStatusCode.PreconditionFailed);

                Assert.AreEqual(HttpStatusCode.PreconditionFailed, batchResponse[0].StatusCode);

                // ensure the document was not updated
                await BatchTestBase.VerifyByReadAsync(container, this.TestDocPk1ExistingB);
            }
        }
        public override TransactionalBatch CreateItemStream(
            Stream streamPayload,
            TransactionalBatchItemRequestOptions requestOptions = null)
        {
            if (requestOptions is EncryptionTransactionalBatchItemRequestOptions encryptionItemRequestOptions &&
                encryptionItemRequestOptions.EncryptionOptions != null)
            {
                CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions);
                using (diagnosticsContext.CreateScope("EncryptItemStream"))
                {
                    streamPayload = EncryptionProcessor.EncryptAsync(
                        streamPayload,
                        this.encryptor,
                        encryptionItemRequestOptions.EncryptionOptions,
                        diagnosticsContext,
                        cancellationToken: default).Result;
                }
            }

            this.transactionalBatch = this.transactionalBatch.CreateItemStream(
                streamPayload,
                requestOptions);

            return(this);
        }
コード例 #3
0
        public async Task NoContentResponseTransactionBatchOverrideTest()
        {
            string             pkId  = "TestBatchId";
            TransactionalBatch batch = this.containerWithFlag.CreateTransactionalBatch(new PartitionKey(pkId));
            TransactionalBatchItemRequestOptions requestOptions = new TransactionalBatchItemRequestOptions()
            {
                EnableContentResponseOnWrite = false
            };

            int noResponseItemCount = 100;

            for (int i = 0; i < noResponseItemCount; i++)
            {
                ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkId);
                batch.CreateItem <ToDoActivity>(item, requestOptions: requestOptions);
            }

            TransactionalBatchResponse response = await batch.ExecuteAsync();

            Assert.AreEqual(response.Count, 100);
            foreach (TransactionalBatchOperationResult itemResponse in response)
            {
                Assert.IsTrue(itemResponse.StatusCode == HttpStatusCode.Created);
                Assert.IsNull(itemResponse.ResourceStream);
            }
        }
        public override TransactionalBatch DeleteItem(string id, TransactionalBatchItemRequestOptions requestOptions = null)
        {
            Guard.AgainstNullAndEmpty(nameof(id), id);

            operationsHolder.AddOperation(new DeleteItemOperation(id, requestOptions, PartitionKey));
            return(this);
        }
        public override TransactionalBatch UpsertItemStream(Stream streamPayload, TransactionalBatchItemRequestOptions requestOptions = null)
        {
            Guard.AgainstNull(nameof(streamPayload), streamPayload);

            operationsHolder.AddOperation(new UpsertItemStreamOperation(streamPayload, requestOptions, PartitionKey));
            return(this);
        }
        public override TransactionalBatch UpsertItem <T>(T item, TransactionalBatchItemRequestOptions requestOptions = null)
        {
            Guard.AgainstNull(nameof(item), item);

            operationsHolder.AddOperation(new UpsertItemOperation <T>(item, requestOptions, PartitionKey));
            return(this);
        }
コード例 #7
0
            private bool Equals(TransactionalBatchItemRequestOptions x, TransactionalBatchItemRequestOptions y)
            {
                if (x == null && y == null)
                {
                    return(true);
                }
                else if (x != null && y != null)
                {
                    RequestMessage xMessage = new RequestMessage();
                    RequestMessage yMessage = new RequestMessage();
                    x.PopulateRequestOptions(xMessage);
                    y.PopulateRequestOptions(yMessage);

                    foreach (string headerName in xMessage.Headers)
                    {
                        if (xMessage.Headers[headerName] != yMessage.Headers[headerName])
                        {
                            return(false);
                        }
                    }

                    return(true);
                }

                return(false);
            }
        public override TransactionalBatch ReplaceItem <T>(string id, T item, TransactionalBatchItemRequestOptions requestOptions = null)
        {
            Guard.AgainstNullAndEmpty(nameof(id), id);
            Guard.AgainstNull(nameof(item), item);

            operationsHolder.AddOperation(new ReplaceItemOperation <T>(id, item, requestOptions, PartitionKey));
            return(this);
        }
コード例 #9
0
        public override TransactionalBatch CreateItemStream(
            Stream streamPayload,
            TransactionalBatchItemRequestOptions requestOptions = null)
        {
            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions);

            using (diagnosticsContext.CreateScope("EncryptItemStream"))
            {
                EncryptionSettings encryptionSettings = this.encryptionContainer.GetOrUpdateEncryptionSettingsFromCacheAsync(obsoleteEncryptionSettings: null, cancellationToken: default)
        public override TransactionalBatch ReadItem(
            string id,
            TransactionalBatchItemRequestOptions requestOptions = null)
        {
            this.transactionalBatch = this.transactionalBatch.ReadItem(
                id,
                requestOptions);

            return(this);
        }
コード例 #11
0
    private static void Store(OrderShippingInformation orderShippingInformation, IMessageHandlerContext context)
    {
        var session        = context.SynchronizedStorageSession.CosmosPersistenceSession();
        var requestOptions = new TransactionalBatchItemRequestOptions
        {
            EnableContentResponseOnWrite = false,
        };

        session.Batch.CreateItem(orderShippingInformation, requestOptions);
    }
コード例 #12
0
        public void FromItemRequestOptions_WithDefaultValues()
        {
            ItemRequestOptions itemRequestOptions = new ItemRequestOptions();
            TransactionalBatchItemRequestOptions batchItemRequestOptions = TransactionalBatchItemRequestOptions.FromItemRequestOptions(itemRequestOptions);

            Assert.AreEqual(itemRequestOptions.IfMatchEtag, batchItemRequestOptions.IfMatchEtag);
            Assert.AreEqual(itemRequestOptions.IfNoneMatchEtag, batchItemRequestOptions.IfNoneMatchEtag);
            Assert.AreEqual(itemRequestOptions.IndexingDirective, batchItemRequestOptions.IndexingDirective);
            Assert.AreEqual(itemRequestOptions.Properties, batchItemRequestOptions.Properties);
        }
コード例 #13
0
        public override TransactionalBatch CreateItem <T>(
            T item,
            TransactionalBatchItemRequestOptions requestOptions = null)
        {
            Stream itemStream = this.cosmosSerializer.ToStream <T>(item);

            return(this.CreateItemStream(
                       itemStream,
                       requestOptions));
        }
コード例 #14
0
        public async Task ItemBatchNoResponseTest()
        {
            TransactionalBatchItemRequestOptions requestOptions = new TransactionalBatchItemRequestOptions()
            {
                EnableContentResponseOnWrite = false
            };

            string             pkId  = "TestBatchId";
            TransactionalBatch batch = this.container.CreateTransactionalBatch(new PartitionKey(pkId));

            int noResponseItemCount = 100;

            for (int i = 0; i < noResponseItemCount; i++)
            {
                ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkId);
                batch.CreateItem <ToDoActivity>(item, requestOptions: requestOptions);
            }

            TransactionalBatchResponse response = await batch.ExecuteAsync();

            Assert.AreEqual(100, response.Count);
            this.ValidateResponse(response, noResponseItemCount);

            pkId  = "TestBatchId2";
            batch = this.container.CreateTransactionalBatch(new PartitionKey(pkId));

            noResponseItemCount = 0;
            for (int i = 0; i < 10; i++)
            {
                ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkId);
                batch.CreateItem <ToDoActivity>(item, requestOptions: requestOptions);
                noResponseItemCount++;
                ToDoActivity item2 = ToDoActivity.CreateRandomToDoActivity(pk: pkId);
                item2.id = item.id;
                batch.ReplaceItem <ToDoActivity>(item2.id, item2, requestOptions);
                noResponseItemCount++;
            }

            int withBodyCount = 0;

            for (int i = 0; i < 5; i++)
            {
                ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkId);
                batch.CreateItem <ToDoActivity>(item);
                withBodyCount++;
                batch.ReadItem(item.id);
                withBodyCount++;
            }

            response = await batch.ExecuteAsync();

            Assert.AreEqual(noResponseItemCount + withBodyCount, response.Count);
            this.ValidateResponse(response, noResponseItemCount);
        }
コード例 #15
0
        internal static TransactionalBatchItemRequestOptions GetBatchItemRequestOptions(TestDoc doc, bool isSchematized, bool useEpk = false, int?ttlInSeconds = null)
        {
            TransactionalBatchItemRequestOptions requestOptions = new TransactionalBatchItemRequestOptions();

            if (PopulateRequestOptions(requestOptions, doc, isSchematized, useEpk, ttlInSeconds))
            {
                return(requestOptions);
            }

            return(null);
        }
コード例 #16
0
 public ItemBatchOperation(
     OperationType operationType,
     int operationIndex,
     PartitionKey partitionKey,
     T resource,
     string id = null,
     TransactionalBatchItemRequestOptions requestOptions = null)
     : base(operationType, operationIndex, partitionKey: partitionKey, id: id, requestOptions: requestOptions)
 {
     this.Resource = resource;
 }
コード例 #17
0
 public ItemBatchOperation(
     OperationType operationType,
     int operationIndex,
     T resource,
     ContainerInternal containerCore,
     string id = null,
     TransactionalBatchItemRequestOptions requestOptions = null)
     : base(operationType, operationIndex, containerCore: containerCore, id: id, requestOptions: requestOptions)
 {
     this.Resource = resource;
 }
コード例 #18
0
        public override TransactionalBatch ReplaceItem <T>(
            string id,
            T item,
            TransactionalBatchItemRequestOptions requestOptions = null)
        {
            Stream itemStream = this.cosmosSerializer.ToStream <T>(item);

            return(this.ReplaceItemStream(
                       id,
                       itemStream,
                       requestOptions));
        }
コード例 #19
0
        public override void Apply(TransactionalBatch transactionalBatch, PartitionKeyPath partitionKeyPath)
        {
            var jObject = ToEnrichedJObject(partitionKeyPath);

            // has to be kept open
            stream = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jObject)));
            var options = new TransactionalBatchItemRequestOptions
            {
                EnableContentResponseOnWrite = false
            };

            transactionalBatch.CreateItemStream(stream, options);
        }
コード例 #20
0
        private static void VerifyBatchItemRequestOptionsAreEqual(TransactionalBatchItemRequestOptions expected, TransactionalBatchItemRequestOptions actual)
        {
            if (expected != null)
            {
                Assert.AreEqual(expected.IfMatchEtag, actual.IfMatchEtag);
                Assert.AreEqual(expected.IfNoneMatchEtag, actual.IfNoneMatchEtag);

                if (expected.IndexingDirective.HasValue)
                {
                    Assert.AreEqual(expected.IndexingDirective.Value, actual.IndexingDirective.Value);
                }
                else
                {
                    Assert.IsTrue(!actual.IndexingDirective.HasValue);
                }

                if (expected.Properties != null)
                {
                    Assert.IsNotNull(actual.Properties);
                    if (expected.Properties.TryGetValue(WFConstants.BackendHeaders.BinaryId, out object expectedBinaryIdObj))
                    {
                        byte[] expectedBinaryId = expectedBinaryIdObj as byte[];
                        Assert.IsTrue(actual.Properties.TryGetValue(WFConstants.BackendHeaders.BinaryId, out object actualBinaryIdObj));
                        byte[] actualBinaryId = actualBinaryIdObj as byte[];
                        CollectionAssert.AreEqual(expectedBinaryId, actualBinaryId);
                    }

                    if (expected.Properties.TryGetValue(WFConstants.BackendHeaders.EffectivePartitionKey, out object expectedEpkObj))
                    {
                        byte[] expectedEpk = expectedEpkObj as byte[];
                        Assert.IsTrue(actual.Properties.TryGetValue(WFConstants.BackendHeaders.EffectivePartitionKey, out object actualEpkObj));
                        byte[] actualEpk = actualEpkObj as byte[];
                        CollectionAssert.AreEqual(expectedEpk, actualEpk);
                    }

                    if (expected.Properties.TryGetValue(WFConstants.BackendHeaders.TimeToLiveInSeconds, out object expectedTtlObj))
                    {
                        string expectedTtlStr = expectedTtlObj as string;
                        Assert.IsTrue(actual.Properties.TryGetValue(WFConstants.BackendHeaders.TimeToLiveInSeconds, out object actualTtlObj));
                        Assert.AreEqual(expectedTtlStr, actualTtlObj as string);
                    }
                }
            }
            else
            {
                Assert.IsNull(actual);
            }
        }
コード例 #21
0
        public void TestWriteOperationWithBinaryIdByteArray()
        {
            ISpanResizer <byte> resizer = new MemorySpanResizer <byte>(100);
            RowBuffer           row     = new RowBuffer(capacity: 100, resizer: resizer);

            row.InitLayout(HybridRowVersion.V1, BatchSchemaProvider.BatchOperationLayout, BatchSchemaProvider.BatchLayoutResolver);

            byte[]             testBinaryId   = new byte[] { 1, 2, 3, 4, };
            ItemRequestOptions requestOptions = new();

            requestOptions.Properties = new Dictionary <string, object>()
            {
                { WFConstants.BackendHeaders.BinaryId, testBinaryId },
            };
            TransactionalBatchItemRequestOptions transactionalBatchItemRequestOptions =
                TransactionalBatchItemRequestOptions.FromItemRequestOptions(requestOptions);
            ItemBatchOperation operation = new ItemBatchOperation(
                operationType: OperationType.Patch,
                operationIndex: 0,
                partitionKey: Cosmos.PartitionKey.Null,
                requestOptions: transactionalBatchItemRequestOptions);

            int length = operation.GetApproximateSerializedLength();

            Assert.AreEqual(testBinaryId.Length, length);

            Result r = RowWriter.WriteBuffer(ref row, operation, ItemBatchOperation.WriteOperation);

            if (r != Result.Success)
            {
                Assert.Fail(r.ToString());
            }

            bool      foundBinaryId = false;
            RowReader reader        = new RowReader(ref row);

            while (reader.Read())
            {
                if (reader.PathSpan == Utf8String.TranscodeUtf16("binaryId"))
                {
                    foundBinaryId = true;
                    reader.ReadBinary(out byte[] binaryId);
                    CollectionAssert.AreEqual(testBinaryId, binaryId);
                }
            }

            Assert.IsTrue(foundBinaryId);
        }
コード例 #22
0
        public async Task MakeTransactionalUpdateAsync(
            string partitionKey,
            CosmosRegisteredEntity[] entitiesToUpsert,
            string[] idsToDelete,
            ILoggerWrapper logger,
            CancellationToken cancellationToken)
        {
            await ExecuteContainerActionAsync(async() =>
            {
                var batch = Container.CreateTransactionalBatch(new PartitionKey(partitionKey));
                foreach (var entity in entitiesToUpsert)
                {
                    TransactionalBatchItemRequestOptions options = null;
                    if (!string.IsNullOrEmpty(entity.ETag))
                    {
                        options = new TransactionalBatchItemRequestOptions
                        {
                            IfMatchEtag = entity.ETag,
                        };
                    }

                    entity.ETag = null;
                    batch.UpsertItem(entity, options);
                }

                foreach (var id in idsToDelete)
                {
                    batch.DeleteItem(id);
                }

                using (var batchResponse = await batch.ExecuteAsync(cancellationToken))
                {
                    if (!batchResponse.IsSuccessStatusCode)
                    {
                        if (batchResponse.StatusCode == HttpStatusCode.PreconditionFailed)
                        {
                            throw new Exception($"Failed to store batch of entities in {partitionKey} as one or more of the updated entities has been " +
                                                $"modified since the last time it was read. This is likely due to a duplicate sync event being received.");
                        }

                        throw new Exception($"Failed to store batch of entities in {partitionKey} " +
                                            $"(Response code: {batchResponse.StatusCode}): {batchResponse.ErrorMessage}");
                    }
                }
            }, logger, cancellationToken);
        }
        internal static TransactionalBatchItemRequestOptions FromItemRequestOptions(ItemRequestOptions itemRequestOptions)
        {
            if (itemRequestOptions == null)
            {
                return(null);
            }

            RequestOptions requestOptions = itemRequestOptions as RequestOptions;
            TransactionalBatchItemRequestOptions batchItemRequestOptions = new TransactionalBatchItemRequestOptions();

            batchItemRequestOptions.IndexingDirective = itemRequestOptions.IndexingDirective;
            batchItemRequestOptions.IfMatchEtag       = requestOptions.IfMatchEtag;
            batchItemRequestOptions.IfNoneMatchEtag   = requestOptions.IfNoneMatchEtag;
            batchItemRequestOptions.Properties        = requestOptions.Properties;
            batchItemRequestOptions.IsEffectivePartitionKeyRouting = requestOptions.IsEffectivePartitionKeyRouting;
            return(batchItemRequestOptions);
        }
コード例 #24
0
    private static OrderShippingInformation StoreOrderShippingInformation(ShipOrder message, IMessageHandlerContext context)
    {
        var transactionalBatch = context.SynchronizedStorageSession.GetSharedTransactionalBatch();
        var requestOptions     = new TransactionalBatchItemRequestOptions
        {
            EnableContentResponseOnWrite = false,
        };

        var orderShippingInformation = new OrderShippingInformation
        {
            Id        = Guid.NewGuid(),
            OrderId   = message.OrderId,
            ShippedAt = DateTimeOffset.UtcNow
        };

        transactionalBatch.CreateItem(orderShippingInformation, requestOptions);
        return(orderShippingInformation);
    }
コード例 #25
0
        public void FromItemRequestOptions_WithCustomValues()
        {
            ItemRequestOptions itemRequestOptions = new ItemRequestOptions();

            itemRequestOptions.IfMatchEtag       = Guid.NewGuid().ToString();
            itemRequestOptions.IfNoneMatchEtag   = Guid.NewGuid().ToString();
            itemRequestOptions.IndexingDirective = Cosmos.IndexingDirective.Exclude;
            itemRequestOptions.Properties        = new Dictionary <string, object>()
            {
                { "test", "test" }
            };

            TransactionalBatchItemRequestOptions batchItemRequestOptions = TransactionalBatchItemRequestOptions.FromItemRequestOptions(itemRequestOptions);

            Assert.AreEqual(itemRequestOptions.IfMatchEtag, batchItemRequestOptions.IfMatchEtag);
            Assert.AreEqual(itemRequestOptions.IfNoneMatchEtag, batchItemRequestOptions.IfNoneMatchEtag);
            Assert.AreEqual(itemRequestOptions.IndexingDirective, batchItemRequestOptions.IndexingDirective);
            Assert.AreEqual(itemRequestOptions.Properties, batchItemRequestOptions.Properties);
        }
コード例 #26
0
        internal static TransactionalBatchItemRequestOptions FromItemRequestOptions(ItemRequestOptions itemRequestOptions)
        {
            if (itemRequestOptions == null)
            {
                return(null);
            }

            RequestOptions requestOptions = itemRequestOptions;
            TransactionalBatchItemRequestOptions batchItemRequestOptions = new TransactionalBatchItemRequestOptions
            {
                IndexingDirective              = itemRequestOptions.IndexingDirective,
                IfMatchEtag                    = itemRequestOptions.IfMatchEtag,
                IfNoneMatchEtag                = itemRequestOptions.IfNoneMatchEtag,
                Properties                     = itemRequestOptions.Properties,
                EnableContentResponseOnWrite   = itemRequestOptions.EnableContentResponseOnWrite,
                IsEffectivePartitionKeyRouting = itemRequestOptions.IsEffectivePartitionKeyRouting
            };

            return(batchItemRequestOptions);
        }
コード例 #27
0
        public override TransactionalBatch CreateItem <T>(
            T item,
            TransactionalBatchItemRequestOptions requestOptions = null)
        {
            if (!(requestOptions is EncryptionTransactionalBatchItemRequestOptions encryptionItemRequestOptions) ||
                encryptionItemRequestOptions.EncryptionOptions == null)
            {
                this.transactionalBatch = this.transactionalBatch.CreateItem(
                    item,
                    requestOptions);

                return(this);
            }

            Stream itemStream = this.cosmosSerializer.ToStream <T>(item);

            return(this.CreateItemStream(
                       itemStream,
                       requestOptions));
        }
        public async Task BatchWithReplaceOfStaleEntityAsync()
        {
            Container container = BatchTestBase.JsonContainer;

            await this.CreateJsonTestDocsAsync(container);

            TestDoc staleTestDocToReplace = this.GetTestDocCopy(this.TestDocPk1ExistingA);

            staleTestDocToReplace.Cost++;
            TransactionalBatchItemRequestOptions staleReplaceOptions = new TransactionalBatchItemRequestOptions()
            {
                IfMatchEtag = Guid.NewGuid().ToString()
            };

            await this.RunWithErrorAsync(
                container,
                batch => batch.ReplaceItem(staleTestDocToReplace.Id, staleTestDocToReplace, staleReplaceOptions),
                HttpStatusCode.PreconditionFailed);

            // make sure the stale doc hasn't changed
            await BatchTestBase.VerifyByReadAsync(container, this.TestDocPk1ExistingA);
        }
コード例 #29
0
        public override TransactionalBatch ReplaceItemStream(
            string id,
            Stream streamPayload,
            TransactionalBatchItemRequestOptions requestOptions = null)
        {
            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions);

            using (diagnosticsContext.CreateScope("EncryptItemStream"))
            {
                streamPayload = this.encryptionProcessor.EncryptAsync(
                    streamPayload,
                    diagnosticsContext,
                    default).Result;
            }

            this.transactionalBatch = this.transactionalBatch.ReplaceItemStream(
                id,
                streamPayload,
                requestOptions);

            return(this);
        }
コード例 #30
0
        async Task CreateOrUpdateInBatch(TransactionalBatch batch)
        {
            if (etag == null)
            {
                batch.CreateItemStream(ToStream(value));
            }
            else
            {
                var options = new TransactionalBatchItemRequestOptions
                {
                    IfMatchEtag = etag
                };
                batch.ReplaceItemStream(TransactionEntityId, ToStream(value), options);
            }

            var response = await batch.ExecuteAsync().ConfigureAwait(false);

            if (!response.IsSuccessStatusCode)
            {
                throw new Exception(response.ToString());
            }
            etag = response.Last().ETag;
        }