Skip to content

Add DynamoDBContext.SaveAsync(Type valueType, object value, ...) #2503

Closed
@ericjpeters

Description

@ericjpeters

Describe the feature

The DynamoDBContext save a SaveAsync(T value, ...) method. There are scenarios where the type is not known at compile-time -- for example, when hooking into EF's ChangeTracker to record audit logs from EF into DynamoDB.

It would be helpful to expose the pre-existing non-generic functionality of DynamoDBContext so that SaveAsync(Type valueType, object value, ...) is possible, as an alternative but equivalent path to SaveAsync(T value, ...) when T is not known at compile-time.

Use Case

There are scenarios where the type is not known at compile-time -- for example, when hooking into EF's ChangeTracker to record audit logs from EF into DynamoDB.

Proposed Solution

I will provide a PR. It's quite trivial.

D:\src\OpenSource\aws-sdk-net [master ≡ +0 ~3 -0 !]> git st
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs
        modified:   sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs
        modified:   sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs

no changes added to commit (use "git add" and/or "git commit -a")
D:\src\OpenSource\aws-sdk-net [master ≡ +0 ~3 -0 !]> git diff sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs
diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs
index ff9bb019e14..0527cc8e714 100644
--- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs
+++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs
@@ -14,14 +14,11 @@
  */
 #pragma warning disable 1574

+using Amazon.DynamoDBv2.DocumentModel;
 using System;
 using System.Collections.Generic;
-using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using Amazon.DynamoDBv2.DocumentModel;
-using Amazon.DynamoDBv2.Model;
-using Amazon.Runtime.Internal;

 namespace Amazon.DynamoDBv2.DataModel
 {
@@ -60,6 +57,33 @@ namespace Amazon.DynamoDBv2.DataModel
             return SaveHelperAsync(value, operationConfig, cancellationToken);
         }

+        /// <summary>
+        /// Initiates the asynchronous execution of the Save operation.
+        /// <seealso cref="Amazon.DynamoDBv2.DataModel.DynamoDBContext.Save"/>
+        /// </summary>
+        /// <param name="valueType">Type of the Object to save.</param>
+        /// <param name="value">Object to save.</param>
+        /// <param name="cancellationToken">Token which can be used to cancel the task.</param>
+        /// <returns>A Task that can be used to poll or wait for results, or both.</returns>
+        public Task SaveAsync(Type valueType, object value, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            return SaveHelperAsync(valueType, value, null, cancellationToken);
+        }
+
+        /// <summary>
+        /// Initiates the asynchronous execution of the Save operation.
+        /// <seealso cref="Amazon.DynamoDBv2.DataModel.DynamoDBContext.Save"/>
+        /// </summary>
+        /// <param name="valueType">Type of the Object to save.</param>
+        /// <param name="value">Object to save.</param>
+        /// <param name="operationConfig">Overriding configuration.</param>
+        /// <param name="cancellationToken">Token which can be used to cancel the task.</param>
+        /// <returns>A Task that can be used to poll or wait for results, or both.</returns>
+        public Task SaveAsync(Type valueType, object value, DynamoDBOperationConfig operationConfig, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            return SaveHelperAsync(valueType, value, operationConfig, cancellationToken);
+        }
+
         #endregion

         #region Load async
D:\src\OpenSource\aws-sdk-net [master ≡ +0 ~3 -0 !]> git diff sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs
diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs
index 97ef6d9c4d7..ab11c25394d 100644
--- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs
+++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs
@@ -14,12 +14,11 @@
  */
 #pragma warning disable 1574

+using Amazon.DynamoDBv2.DocumentModel;
 using System;
 using System.Collections.Generic;
 using System.Threading;
 using System.Threading.Tasks;
-using Amazon.DynamoDBv2.DocumentModel;
-using Amazon.DynamoDBv2.Model;

 namespace Amazon.DynamoDBv2.DataModel
 {
@@ -52,6 +51,27 @@ namespace Amazon.DynamoDBv2.DataModel
         /// <returns>A Task that can be used to poll or wait for results, or both.</returns>
         Task SaveAsync<T>(T value, DynamoDBOperationConfig operationConfig, CancellationToken cancellationToken = default(CancellationToken));

+        /// <summary>
+        /// Initiates the asynchronous execution of the Save operation.
+        /// <seealso cref="Amazon.DynamoDBv2.DataModel.DynamoDBContext.Save"/>
+        /// </summary>
+        /// <param name="valueType">Type of the Object to save.</param>
+        /// <param name="value">Object to save.</param>
+        /// <param name="cancellationToken">Token which can be used to cancel the task.</param>
+        /// <returns>A Task that can be used to poll or wait for results, or both.</returns>
+        Task SaveAsync(Type valueType, object value, CancellationToken cancellationToken = default(CancellationToken));
+
+        /// <summary>
+        /// Initiates the asynchronous execution of the Save operation.
+        /// <seealso cref="Amazon.DynamoDBv2.DataModel.DynamoDBContext.Save"/>
+        /// </summary>
+        /// <param name="valueType">Type of the Object to save.</param>
+        /// <param name="value">Object to save.</param>
+        /// <param name="operationConfig">Overriding configuration.</param>
+        /// <param name="cancellationToken">Token which can be used to cancel the task.</param>
+        /// <returns>A Task that can be used to poll or wait for results, or both.</returns>
+        Task SaveAsync(Type valueType, object value, DynamoDBOperationConfig operationConfig, CancellationToken cancellationToken = default(CancellationToken));
+
         #endregion

         #region Load async
D:\src\OpenSource\aws-sdk-net [master ≡ +0 ~3 -0 !]> git diff sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs
diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs
index d44902ae66a..c69cf281d98 100644
--- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs
+++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs
@@ -19,7 +19,6 @@ using System.Threading;
 #if AWS_ASYNC_API
 using System.Threading.Tasks;
 #endif
-using Amazon.DynamoDBv2;
 using Amazon.DynamoDBv2.DocumentModel;

 namespace Amazon.DynamoDBv2.DataModel
@@ -297,6 +296,34 @@ namespace Amazon.DynamoDBv2.DataModel
                 PopulateInstance(storage, value, flatConfig);
             }
         }
+
+        private async Task SaveHelperAsync(Type valueType, object value, DynamoDBOperationConfig operationConfig, CancellationToken cancellationToken)
+        {
+            if (value == null) return;
+
+            DynamoDBFlatConfig flatConfig = new DynamoDBFlatConfig(operationConfig, this.Config);
+            ItemStorage storage = ObjectToItemStorage(value, valueType, false, flatConfig);
+            if (storage == null) return;
+
+            Table table = GetTargetTable(storage.Config, flatConfig);
+            if (
+                (flatConfig.SkipVersionCheck.HasValue && flatConfig.SkipVersionCheck.Value)
+                || !storage.Config.HasVersion)
+            {
+                await table.UpdateHelperAsync(storage.Document, table.MakeKey(storage.Document), null, cancellationToken).ConfigureAwait(false);
+            }
+            else
+            {
+                Document expectedDocument = CreateExpectedDocumentForVersion(storage);
+                SetNewVersion(storage);
+                await table.UpdateHelperAsync(
+                    storage.Document,
+                    table.MakeKey(storage.Document),
+                    new UpdateItemOperationConfig { Expected = expectedDocument, ReturnValues = ReturnValues.None },
+                    cancellationToken).ConfigureAwait(false);
+                PopulateInstance(storage, value, flatConfig);
+            }
+        }
 #endif

         /// <summary>

Other Information

No response

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

AWS .NET SDK and/or Package version used

AWSSDK.DynamoDBv2 v3.7.101.10

Targeted .NET Platform

.NET 7

Operating System and version

Windows 11 22H2

Metadata

Metadata

Assignees

No one assigned

    Labels

    dynamodbfeature-requestA feature should be added or improved.p2This is a standard priority issuequeued

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions