diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs
index 329ad6834b2f..003508451426 100644
--- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs
+++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs
@@ -103,6 +103,7 @@ public void RegisterTableDefinition(Table table)
/// Constructs a DynamoDBContext object with a default AmazonDynamoDBClient
/// client and a default DynamoDBContextConfig object for configuration.
///
+ [Obsolete("Use the DynamoDBContextBuilder to construct a DynamoDBContext with the recommended configuration.")]
public DynamoDBContext()
: this(new AmazonDynamoDBClient()) { }
@@ -111,6 +112,7 @@ public DynamoDBContext()
/// client and a default DynamoDBContextConfig object for configuration.
///
/// The region to configure the AmazonDynamoDBClient to use.
+ [Obsolete("Use the DynamoDBContextBuilder to construct a DynamoDBContext with the recommended configuration.")]
public DynamoDBContext(RegionEndpoint region)
: this(new AmazonDynamoDBClient(region), true, new DynamoDBContextConfig()) { }
@@ -119,6 +121,7 @@ public DynamoDBContext(RegionEndpoint region)
/// Uses a default AmazonDynamoDBClient as the client.
///
///
+ [Obsolete("Use the DynamoDBContextBuilder to construct a DynamoDBContext with the recommended configuration.")]
public DynamoDBContext(DynamoDBContextConfig config)
: this(new AmazonDynamoDBClient(), config) { }
@@ -128,6 +131,7 @@ public DynamoDBContext(DynamoDBContextConfig config)
///
/// The region to configure the AmazonDynamoDBClient to use.
///
+ [Obsolete("Use the DynamoDBContextBuilder to construct a DynamoDBContext with the recommended configuration.")]
public DynamoDBContext(RegionEndpoint region, DynamoDBContextConfig config)
: this(new AmazonDynamoDBClient(region), true, config) { }
#endif
@@ -137,6 +141,7 @@ public DynamoDBContext(RegionEndpoint region, DynamoDBContextConfig config)
/// Uses default DynamoDBContextConfig object for configuration.
///
/// Client to use for making calls
+ [Obsolete("Use the DynamoDBContextBuilder to construct a DynamoDBContext with the recommended configuration.")]
public DynamoDBContext(IAmazonDynamoDB client)
: this(client, false, new DynamoDBContextConfig()) { }
@@ -146,10 +151,11 @@ public DynamoDBContext(IAmazonDynamoDB client)
///
/// Client to use for making calls
/// Configuration to use
+ [Obsolete("Use the DynamoDBContextBuilder to construct a DynamoDBContext with the recommended configuration.")]
public DynamoDBContext(IAmazonDynamoDB client, DynamoDBContextConfig config)
: this(client, false, config) { }
- private DynamoDBContext(IAmazonDynamoDB client, bool ownClient, DynamoDBContextConfig config)
+ internal DynamoDBContext(IAmazonDynamoDB client, bool ownClient, DynamoDBContextConfig config)
{
if (client == null) throw new ArgumentNullException("client");
diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/ContextBuilder.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/ContextBuilder.cs
new file mode 100644
index 000000000000..0ffe72e69eed
--- /dev/null
+++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/ContextBuilder.cs
@@ -0,0 +1,81 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+using System;
+
+namespace Amazon.DynamoDBv2.DataModel
+{
+ ///
+#if NET8_0_OR_GREATER
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(Amazon.DynamoDBv2.Custom.Internal.InternalConstants.RequiresUnreferencedCodeMessage)]
+#endif
+ public class DynamoDBContextBuilder : IDynamoDBContextBuilder
+ {
+ ///
+ /// The object that is built and then supplied to the returned
+ ///
+ private DynamoDBContextConfig _config;
+
+ ///
+ /// A factory method for creating a client
+ ///
+ private Func _clientFactory;
+
+ ///
+ /// Creates a builder object to construct a
+ ///
+ public DynamoDBContextBuilder()
+ {
+ _config = new DynamoDBContextConfig();
+ _config.DisableFetchingTableMetadata = true;
+ }
+
+ ///
+ public IDynamoDBContextBuilder ConfigureContext(Action configure)
+ {
+ configure(_config);
+
+ return this;
+ }
+
+ ///
+ public IDynamoDBContextBuilder WithDynamoDBClient(Func factory)
+ {
+ _clientFactory = factory;
+
+ return this;
+ }
+
+ ///
+ public DynamoDBContext Build()
+ {
+ IAmazonDynamoDB client;
+ bool ownClient;
+
+ if (_clientFactory is null)
+ {
+ client = new AmazonDynamoDBClient();
+ ownClient = true;
+ }
+ else
+ {
+ client = _clientFactory.Invoke();
+ ownClient = false;
+ }
+
+ return new DynamoDBContext(client, ownClient, _config);
+ }
+ }
+}
diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/ContextInternal.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/ContextInternal.cs
index 447c52c65dcd..3d0431f664cc 100644
--- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/ContextInternal.cs
+++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/ContextInternal.cs
@@ -147,6 +147,9 @@ internal Table GetTargetTable(ItemStorageConfig storageConfig, DynamoDBFlatConfi
return table;
}
+// This is the call we want to avoid with disableFetchingTableMetadata = true, but as long as we still support false, we still need to call the discouraged sync-over-async 'Table.LoadTable(Client, emptyConfig)'
+#pragma warning disable CS0618
+
// Retrieves Config-less Table from cache or constructs it on cache-miss
// This Table should not be used for data operations.
// To use for data operations, Copy with a TableConfig first.
@@ -203,6 +206,8 @@ internal Table GetUnconfiguredTable(string tableName, bool disableFetchingTableM
}
}
+#pragma warning restore CS0618
+
///
/// Stores a table in the cache if there is not an existing entry for the given key
///
diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/IDynamoDBContextBuilder.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/IDynamoDBContextBuilder.cs
new file mode 100644
index 000000000000..a48596d2d717
--- /dev/null
+++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/IDynamoDBContextBuilder.cs
@@ -0,0 +1,59 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+using System;
+
+namespace Amazon.DynamoDBv2.DataModel
+{
+ ///
+ /// Interface for a builder that constructs a
+ /// Using to construct a will implicitly set
+ /// to true which avoids the DescribeTable call
+ /// and relies entirely on the DynamoDB attributes set on the .NET classes. Alternatively, you can register the
+ /// table definition using .
+ /// If needed, you can revert back to the previous behavior by setting
+ /// to false using as such:
+ ///
+ /// var context = new DynamoDBContextBuilder()
+ /// .ConfigureContext(x =>
+ /// {
+ /// x.DisableFetchingTableMetadata = false;
+ /// })
+ /// .Build();
+ ///
+ ///
+ public interface IDynamoDBContextBuilder
+ {
+ ///
+ /// Supplies a factory method for creating a client.
+ /// If a factory method is not provided, a new client
+ /// will be created using the environment to search for credentials and region configuration.
+ ///
+ /// Factory method for creating a client
+ IDynamoDBContextBuilder WithDynamoDBClient(Func factory);
+
+ ///
+ /// Configures the that is being constructed
+ ///
+ /// The configuration applied to the constructed
+ IDynamoDBContextBuilder ConfigureContext(Action configure);
+
+ ///
+ /// Call at the end to retrieve the new
+ ///
+ /// Built
+ DynamoDBContext Build();
+ }
+}
diff --git a/sdk/src/Services/DynamoDBv2/Custom/DocumentModel/Table.cs b/sdk/src/Services/DynamoDBv2/Custom/DocumentModel/Table.cs
index 6a30637db5f6..17c04ce926c9 100644
--- a/sdk/src/Services/DynamoDBv2/Custom/DocumentModel/Table.cs
+++ b/sdk/src/Services/DynamoDBv2/Custom/DocumentModel/Table.cs
@@ -443,6 +443,7 @@ public static void ClearTableCache()
/// Client to use to access DynamoDB.
/// Configuration to use for the table.
/// Table object representing the specified table.
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static Table LoadTable(IAmazonDynamoDB ddbClient, TableConfig config)
{
Table table = new Table(ddbClient, config);
@@ -648,6 +649,7 @@ internal static Table CreateTableFromItemStorageConfig(IAmazonDynamoDB client, T
/// Client to use to access DynamoDB.
/// Name of the table.
/// Table object representing the specified table.
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName)
{
return LoadTable(ddbClient, tableName, DynamoDBEntryConversion.CurrentConversion, false);
@@ -663,6 +665,7 @@ public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName)
/// Name of the table.
/// Conversion to use for converting .NET values to DynamoDB values.
/// Table object representing the specified table.
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName, DynamoDBEntryConversion conversion)
{
return LoadTable(ddbClient, tableName, conversion, false);
@@ -678,6 +681,7 @@ public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName, Dynam
/// Name of the table.
/// If the property is false, empty string values will be interpreted as null values.
/// Table object representing the specified table.
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName, bool isEmptyStringValueEnabled)
{
return LoadTable(ddbClient, tableName, DynamoDBEntryConversion.CurrentConversion, isEmptyStringValueEnabled);
@@ -694,6 +698,7 @@ public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName, bool
/// Conversion to use for converting .NET values to DynamoDB values.
/// If the property is false, empty string values will be interpreted as null values.
/// Table object representing the specified table.
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName, DynamoDBEntryConversion conversion, bool isEmptyStringValueEnabled)
{
var config = new TableConfig(tableName, conversion, DynamoDBConsumer.DocumentModel, storeAsEpoch: null, isEmptyStringValueEnabled: isEmptyStringValueEnabled, metadataCachingMode: MetadataCachingMode.Default);
@@ -715,6 +720,7 @@ public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName, Dynam
/// requests. This controls how the cache key is derived, which influences when the SDK will call
/// IAmazonDynamoDB.DescribeTable(string) internally to populate the cache.
/// Table object representing the specified table.
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName, DynamoDBEntryConversion conversion, bool isEmptyStringValueEnabled, MetadataCachingMode metadataCachingMode)
{
var config = new TableConfig(tableName, conversion, DynamoDBConsumer.DocumentModel, storeAsEpoch: null, isEmptyStringValueEnabled: isEmptyStringValueEnabled, metadataCachingMode: metadataCachingMode);
@@ -736,6 +742,7 @@ public static Table LoadTable(IAmazonDynamoDB ddbClient, string tableName, Dynam
///
/// True if table was successfully loaded; otherwise false.
///
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static bool TryLoadTable(IAmazonDynamoDB ddbClient, string tableName, out Table table)
{
return TryLoadTable(ddbClient, tableName, DynamoDBEntryConversion.CurrentConversion, false, out table);
@@ -754,6 +761,7 @@ public static bool TryLoadTable(IAmazonDynamoDB ddbClient, string tableName, out
///
/// True if table was successfully loaded; otherwise false.
///
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static bool TryLoadTable(IAmazonDynamoDB ddbClient, string tableName, DynamoDBEntryConversion conversion, out Table table)
{
return TryLoadTable(ddbClient, tableName, conversion, false, out table);
@@ -772,6 +780,7 @@ public static bool TryLoadTable(IAmazonDynamoDB ddbClient, string tableName, Dyn
///
/// True if table was successfully loaded; otherwise false.
///
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static bool TryLoadTable(IAmazonDynamoDB ddbClient, string tableName, bool isEmptyStringValueEnabled, out Table table)
{
return TryLoadTable(ddbClient, tableName, DynamoDBEntryConversion.CurrentConversion, isEmptyStringValueEnabled, out table);
@@ -791,6 +800,7 @@ public static bool TryLoadTable(IAmazonDynamoDB ddbClient, string tableName, boo
///
/// True if table was successfully loaded; otherwise false.
///
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static bool TryLoadTable(IAmazonDynamoDB ddbClient, string tableName, DynamoDBEntryConversion conversion, bool isEmptyStringValueEnabled, out Table table)
{
return TryLoadTable(ddbClient, tableName, conversion, isEmptyStringValueEnabled, MetadataCachingMode.Default, out table);
@@ -813,6 +823,7 @@ public static bool TryLoadTable(IAmazonDynamoDB ddbClient, string tableName, Dyn
///
/// True if table was successfully loaded; otherwise false.
///
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static bool TryLoadTable(IAmazonDynamoDB ddbClient,
string tableName,
DynamoDBEntryConversion conversion,
@@ -842,6 +853,7 @@ public static bool TryLoadTable(IAmazonDynamoDB ddbClient,
///
/// True if table was successfully loaded; otherwise false.
///
+ [Obsolete("Use the TableBuilder to construct a Table with the recommended configuration.")]
public static bool TryLoadTable(IAmazonDynamoDB ddbClient, TableConfig config, out Table table)
{
if (config == null)
diff --git a/sdk/test/Services/DynamoDBv2/IntegrationTests/Cache.cs b/sdk/test/Services/DynamoDBv2/IntegrationTests/Cache.cs
index d146ab3e86a4..6f48710b2e86 100644
--- a/sdk/test/Services/DynamoDBv2/IntegrationTests/Cache.cs
+++ b/sdk/test/Services/DynamoDBv2/IntegrationTests/Cache.cs
@@ -103,11 +103,15 @@ public void MultipleClientsTest()
Table table;
using (var nc = new AmazonDynamoDBClient())
{
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
table = Table.LoadTable(nc, tableName);
+#pragma warning restore CS0618 // Re-enable the warning
}
Table.ClearTableCache();
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
table = Table.LoadTable(client, tableName);
+#pragma warning restore CS0618 // Re-enable the warning
}
[TestMethod]
@@ -123,7 +127,9 @@ public void ChangingTableTest()
var tableCache = SdkCache.GetCache(client, DynamoDBTests.TableCacheIdentifier, StringComparer.Ordinal);
CreateTable(TABLENAME, defaultKeys: true);
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
var table = Table.LoadTable(client, TABLENAME);
+#pragma warning restore CS0618 // Re-enable the warning
table.PutItem(item);
using (var counter = new ServiceResponseCounter(client))
@@ -144,7 +150,9 @@ public void ChangingTableTest()
counter.Reset();
Table.ClearTableCache();
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
table = Table.LoadTable(client, TABLENAME);
+#pragma warning restore CS0618 // Re-enable the warning
doc = table.GetItem(42, "Yes");
Assert.IsNotNull(doc);
Assert.AreNotEqual(0, doc.Count);
@@ -153,11 +161,13 @@ public void ChangingTableTest()
counter.Reset();
Table.ClearTableCache();
PutItem(tableCache, TABLENAME, oldTableDescription);
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
table = Table.LoadTable(client, TABLENAME);
doc = tableCache.UseCache(TABLENAME,
() => table.GetItem(42, "Yes"),
() => table = Table.LoadTable(client, TABLENAME),
shouldRetryForException: null);
+#pragma warning restore CS0618 // Re-enable the warning
Assert.IsNotNull(doc);
Assert.AreNotEqual(0, doc.Count);
diff --git a/sdk/test/Services/DynamoDBv2/IntegrationTests/DataModelTests.cs b/sdk/test/Services/DynamoDBv2/IntegrationTests/DataModelTests.cs
index 078ea6d7e3a7..aa8da86a6764 100644
--- a/sdk/test/Services/DynamoDBv2/IntegrationTests/DataModelTests.cs
+++ b/sdk/test/Services/DynamoDBv2/IntegrationTests/DataModelTests.cs
@@ -202,7 +202,9 @@ public void TestContext_RetrieveDateTimeInUtc(bool retrieveDateTimeInUtc)
Conversion = DynamoDBEntryConversion.V2,
RetrieveDateTimeInUtc = retrieveDateTimeInUtc
};
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
Context = new DynamoDBContext(Client, config);
+#pragma warning restore CS0618 // Re-enable the warning
var currTime = DateTime.Now;
@@ -271,7 +273,9 @@ public void TestContext_CustomDateTimeConverter(bool retrieveDateTimeInUtc)
Conversion = DynamoDBEntryConversion.V2,
RetrieveDateTimeInUtc = retrieveDateTimeInUtc
};
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
Context = new DynamoDBContext(Client, config);
+#pragma warning restore CS0618 // Re-enable the warning
// Add a custom DateTime converter
Context.ConverterCache.Add(typeof(DateTime), new DateTimeUtcConverter());
@@ -340,7 +344,9 @@ public void TestContext_RetrieveDateTimeInUtc_OperationConfig(bool retrieveDateT
CleanupTables();
TableCache.Clear();
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
Context = new DynamoDBContext(Client, new DynamoDBContextConfig { Conversion = DynamoDBEntryConversion.V2 });
+#pragma warning restore CS0618 // Re-enable the warning
var operationConfig = new DynamoDBOperationConfig { RetrieveDateTimeInUtc = retrieveDateTimeInUtc };
var currTime = DateTime.Now;
@@ -411,12 +417,14 @@ public void TestWithBuilderTables()
// Clear existing SDK-wide cache
TableCache.Clear();
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
// Redeclare Context, which will start with empty caches
Context = new DynamoDBContext(Client, new DynamoDBContextConfig
{
IsEmptyStringValueEnabled = true,
Conversion = conversion
});
+#pragma warning restore CS0618 // Re-enable the warning
Context.RegisterTableDefinition(new TableBuilder(Client, "DotNetTests-HashRangeTable")
.AddHashKey("Name", DynamoDBEntryType.String)
@@ -455,6 +463,50 @@ public void TestWithBuilderTables()
}
}
+ ///
+ /// Runs the same object-mapper integration tests as ,
+ /// but using a DynamoDBContext created by
+ ///
+ [TestMethod]
+ [TestCategory("DynamoDBv2")]
+ public void TestWithBuilderContext()
+ {
+ foreach (var conversion in new DynamoDBEntryConversion[] { DynamoDBEntryConversion.V1, DynamoDBEntryConversion.V2 })
+ {
+ // Cleanup existing data in the tables
+ CleanupTables();
+
+ // Clear existing SDK-wide cache
+ TableCache.Clear();
+
+ Context = new DynamoDBContextBuilder()
+ .ConfigureContext(x =>
+ {
+ x.IsEmptyStringValueEnabled = true;
+ x.Conversion = conversion;
+ })
+ .Build();
+
+ TestEmptyStringsWithFeatureEnabled();
+
+ TestEnumHashKeyObjects();
+
+ TestEmptyCollections(conversion);
+
+ TestAnnotatedUnsupportedTypes();
+ TestEnums(conversion);
+
+ TestHashObjects();
+ TestHashRangeObjects();
+ TestOtherContextOperations();
+ TestBatchOperations();
+ TestAnnotatedTransactionOperations();
+ TestAnnotatedMultiTableTransactionOperations();
+
+ TestStoreAsAnnotatedEpoch();
+ }
+ }
+
private static void TestEmptyStringsWithFeatureEnabled()
{
var product = new Product
@@ -575,6 +627,37 @@ private static void TestUnsupportedTypes()
"Type AWSSDK_DotNet.IntegrationTests.Tests.DynamoDB.DynamoDBTests+EmptyType is unsupported, it has no supported members");
}
+ private static void TestAnnotatedUnsupportedTypes()
+ {
+ // Verify that saving objects with invalid properties result in exceptions
+ var employee4 = new Employee4
+ {
+ Name = "Alan",
+ Age = 31,
+ TimeWithCompany = TimeSpan.FromDays(300)
+ };
+ AssertExtensions.ExpectException(() => Context.Save(employee4),
+ typeof(InvalidOperationException),
+ "Type System.TimeSpan is unsupported, it cannot be instantiated");
+ var employee5 = new Employee5
+ {
+ Name = "Alan",
+ Age = 31,
+ EmptyProperty = new EmptyType()
+ };
+ AssertExtensions.ExpectException(() => Context.Save(employee5),
+ typeof(InvalidOperationException),
+ "Type AWSSDK_DotNet.IntegrationTests.Tests.DynamoDB.DynamoDBTests+EmptyType is unsupported, it has no supported members");
+
+ // Verify that objects that are invalid result in exceptions
+ AssertExtensions.ExpectException(() => Context.Scan(),
+ typeof(InvalidOperationException),
+ "Type System.TimeSpan is unsupported, it cannot be instantiated");
+ AssertExtensions.ExpectException(() => Context.Scan(),
+ typeof(InvalidOperationException),
+ "Type AWSSDK_DotNet.IntegrationTests.Tests.DynamoDB.DynamoDBTests+EmptyType is unsupported, it has no supported members");
+ }
+
private void TestContextConversions()
{
var conversionV1 = DynamoDBEntryConversion.V1;
@@ -612,6 +695,7 @@ private void TestContextConversions()
}
{
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
using (var contextV1 = new DynamoDBContext(Client, new DynamoDBContextConfig { Conversion = conversionV1 }))
using (var contextV2 = new DynamoDBContext(Client, new DynamoDBContextConfig { Conversion = conversionV2 }))
{
@@ -619,14 +703,17 @@ private void TestContextConversions()
var docV2 = contextV2.ToDocument(product);
VerifyConversions(docV1, docV2);
}
+#pragma warning restore CS0618 // Re-enable the warning
}
{
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
using (var contextV1 = new DynamoDBContext(Client, new DynamoDBContextConfig { Conversion = conversionV1 }))
{
contextV1.Save(product);
contextV1.Save(product, new SaveConfig { Conversion = conversionV2 });
}
+#pragma warning restore CS0618 // Re-enable the warning
}
// Introduce a circular reference and try to serialize
@@ -1534,6 +1621,209 @@ private void TestTransactionOperations()
}
}
+ private void TestAnnotatedTransactionOperations()
+ {
+ var employee1 = new VersionedAnnotatedEmployee
+ {
+ Name = "Mark",
+ Age = 31,
+ Score = 120,
+ ManagerName = "Harmony"
+ };
+ var employee2 = new VersionedAnnotatedEmployee
+ {
+ Name = "Helena",
+ Age = 25,
+ Score = 140
+ };
+ var employee3 = new VersionedAnnotatedEmployee
+ {
+ Name = "Irving",
+ Age = 55,
+ Score = 100
+ };
+
+ {
+ var transactWrite = Context.CreateTransactWrite();
+ transactWrite.AddSaveItems(new List { employee1, employee2 });
+ transactWrite.AddSaveItem(employee3);
+ transactWrite.Execute();
+
+ Assert.IsNotNull(employee1.Version);
+ Assert.IsNotNull(employee2.Version);
+ Assert.IsNotNull(employee3.Version);
+ }
+
+ {
+ var transactGet = Context.CreateTransactGet();
+ transactGet.AddKeys(new List { employee1, employee2 });
+ transactGet.AddKey(employee3.Name, employee3.Age);
+ transactGet.Execute();
+
+ Assert.IsNotNull(transactGet.Results);
+ Assert.AreEqual(3, transactGet.Results.Count);
+ Assert.AreEqual(employee1.Name, transactGet.Results[0].Name);
+ Assert.AreEqual(employee1.Version, transactGet.Results[0].Version);
+ Assert.AreEqual(employee2.Name, transactGet.Results[1].Name);
+ Assert.AreEqual(employee2.Version, transactGet.Results[1].Version);
+ Assert.AreEqual(employee3.Name, transactGet.Results[2].Name);
+ Assert.AreEqual(employee3.Version, transactGet.Results[2].Version);
+ }
+
+ {
+ var originalVersion = employee1.Version.Value;
+ employee1.Version = null;
+ employee1.Score++;
+
+ var transactWrite = Context.CreateTransactWrite();
+ transactWrite.AddSaveItem(employee1);
+ transactWrite.AddVersionCheckKey(employee2.Name, employee2.Age, employee2.Version);
+ transactWrite.AddDeleteItem(employee3);
+ var ex = AssertExtensions.ExpectException(() => transactWrite.Execute());
+
+ Assert.IsNotNull(ex.CancellationReasons);
+ Assert.AreEqual(3, ex.CancellationReasons.Count);
+ Assert.AreEqual("ConditionalCheckFailed", ex.CancellationReasons[0].Code);
+ Assert.AreEqual("None", ex.CancellationReasons[1].Code);
+ Assert.AreEqual("None", ex.CancellationReasons[2].Code);
+
+ employee1.Version = originalVersion;
+ employee1.Score--;
+ }
+
+ {
+ var transactGet = Context.CreateTransactGet();
+ transactGet.AddKey(employee1);
+ transactGet.AddKeys(new List { employee2, employee3 });
+ transactGet.Execute();
+
+ Assert.IsNotNull(transactGet.Results);
+ Assert.AreEqual(3, transactGet.Results.Count);
+ Assert.AreEqual(employee1.Score, transactGet.Results[0].Score);
+ Assert.AreEqual(employee1.Version, transactGet.Results[0].Version);
+ Assert.AreEqual(employee2.Version, transactGet.Results[1].Version);
+ Assert.AreEqual(employee3.Version, transactGet.Results[2].Version);
+ }
+
+ {
+ employee1.Score++;
+ employee2.Version++;
+
+ var transactWrite = Context.CreateTransactWrite();
+ transactWrite.AddSaveItem(employee1);
+ transactWrite.AddVersionCheckItem(employee2);
+ transactWrite.AddDeleteItem(employee3);
+ var ex = AssertExtensions.ExpectException(() => transactWrite.Execute());
+
+ Assert.IsNotNull(ex.CancellationReasons);
+ Assert.AreEqual(3, ex.CancellationReasons.Count);
+ Assert.AreEqual("None", ex.CancellationReasons[0].Code);
+ Assert.AreEqual("ConditionalCheckFailed", ex.CancellationReasons[1].Code);
+ Assert.AreEqual("None", ex.CancellationReasons[2].Code);
+
+ employee1.Score--;
+ employee2.Version--;
+ }
+
+ {
+ var transactGet = Context.CreateTransactGet();
+ transactGet.AddKeys(new List { employee1, employee2 });
+ transactGet.AddKey(employee3.Name, employee3.Age);
+ transactGet.Execute();
+
+ Assert.IsNotNull(transactGet.Results);
+ Assert.AreEqual(3, transactGet.Results.Count);
+ Assert.AreEqual(employee1.Score, transactGet.Results[0].Score);
+ Assert.AreEqual(employee1.Version, transactGet.Results[0].Version);
+ Assert.AreEqual(employee2.Version, transactGet.Results[1].Version);
+ Assert.AreEqual(employee3.Version, transactGet.Results[2].Version);
+ }
+
+ {
+ employee1.Score++;
+ employee3.Version--;
+
+ var transactWrite = Context.CreateTransactWrite();
+ transactWrite.AddSaveItem(employee1);
+ transactWrite.AddVersionCheckKey(employee2.Name, employee2.Age, employee2.Version);
+ transactWrite.AddDeleteItem(employee3);
+ var ex = AssertExtensions.ExpectException(() => transactWrite.Execute());
+
+ Assert.IsNotNull(ex.CancellationReasons);
+ Assert.AreEqual(3, ex.CancellationReasons.Count);
+ Assert.AreEqual("None", ex.CancellationReasons[0].Code);
+ Assert.AreEqual("None", ex.CancellationReasons[1].Code);
+ Assert.AreEqual("ConditionalCheckFailed", ex.CancellationReasons[2].Code);
+
+ employee1.Score--;
+ employee3.Version++;
+ }
+
+ {
+ var transactGet = Context.CreateTransactGet();
+ transactGet.AddKey(employee1);
+ transactGet.AddKeys(new List { employee2, employee3 });
+ transactGet.Execute();
+
+ Assert.IsNotNull(transactGet.Results);
+ Assert.AreEqual(3, transactGet.Results.Count);
+ Assert.AreEqual(employee1.Score, transactGet.Results[0].Score);
+ Assert.AreEqual(employee1.Version, transactGet.Results[0].Version);
+ Assert.AreEqual(employee2.Version, transactGet.Results[1].Version);
+ Assert.AreEqual(employee3.Version, transactGet.Results[2].Version);
+ }
+
+ {
+ var originalVersion1 = employee1.Version.Value;
+ var originalVersion2 = employee2.Version.Value;
+ var originalVersion3 = employee3.Version.Value;
+ employee1.Score++;
+ employee1.ManagerName = null;
+
+ var transactWrite = Context.CreateTransactWrite();
+ transactWrite.AddSaveItem(employee1);
+ transactWrite.AddVersionCheckItem(employee2);
+ transactWrite.AddDeleteItem(employee3);
+ transactWrite.Execute();
+
+ Assert.AreEqual(originalVersion1 + 1, employee1.Version);
+ Assert.AreEqual(originalVersion2, employee2.Version);
+ Assert.AreEqual(originalVersion3, employee3.Version);
+ }
+
+ {
+ var transactGet = Context.CreateTransactGet();
+ transactGet.AddKeys(new List { employee1, employee2 });
+ transactGet.AddKey(employee3.Name, employee3.Age);
+ transactGet.Execute();
+
+ Assert.IsNotNull(transactGet.Results);
+ Assert.AreEqual(2, transactGet.Results.Count);
+ Assert.AreEqual(employee1.Name, transactGet.Results[0].Name);
+ Assert.AreEqual(employee1.Score, transactGet.Results[0].Score);
+ Assert.IsNull(transactGet.Results[0].ManagerName);
+ Assert.AreEqual(employee1.Version, transactGet.Results[0].Version);
+ Assert.AreEqual(employee2.Name, transactGet.Results[1].Name);
+ Assert.AreEqual(employee2.Version, transactGet.Results[1].Version);
+ }
+
+ {
+ var transactWrite = Context.CreateTransactWrite();
+ transactWrite.AddDeleteItem(employee1);
+ transactWrite.AddDeleteKey(employee2.Name, employee2.Age);
+ transactWrite.Execute();
+ }
+
+ {
+ var transactGet = Context.CreateTransactGet();
+ transactGet.AddKeys(new List { employee1, employee2, employee3 });
+ transactGet.Execute();
+
+ Assert.IsNotNull(transactGet.Results);
+ Assert.AreEqual(0, transactGet.Results.Count);
+ }
+ }
+
private void TestMultiTableTransactionOperations()
{
var employee1 = new VersionedEmployee
@@ -1691,6 +1981,163 @@ private void TestMultiTableTransactionOperations()
}
}
+ private void TestAnnotatedMultiTableTransactionOperations()
+ {
+ var employee1 = new VersionedAnnotatedEmployee
+ {
+ Name = "Alan",
+ Age = 31,
+ Score = 120,
+ ManagerName = "Barbara"
+ };
+ var employee2 = new VersionedAnnotatedEmployee
+ {
+ Name = "Diane",
+ Age = 40,
+ Score = 140
+ };
+ var product = new VersionedProduct
+ {
+ Id = 1001,
+ Name = "CloudSpotter",
+ Price = 1200
+ };
+
+ {
+ var employeeTran = Context.CreateTransactWrite();
+ employeeTran.AddSaveItems(new[] { employee1, employee2 });
+ var productTran = Context.CreateTransactWrite();
+ productTran.AddSaveItem(product);
+ var tran = Context.CreateMultiTableTransactWrite(employeeTran, productTran);
+ tran.Execute();
+
+ Assert.IsNotNull(employee1.Version);
+ Assert.IsNotNull(employee2.Version);
+ Assert.IsNotNull(product.Version);
+ }
+
+ {
+ var employeeTran = Context.CreateTransactGet();
+ employeeTran.AddKeys(new[] { employee1, employee2 });
+ var productTran = Context.CreateTransactGet();
+ productTran.AddKey(product.Id);
+ var tran = Context.CreateMultiTableTransactGet(employeeTran, productTran);
+ tran.Execute();
+
+ Assert.IsNotNull(employeeTran.Results);
+ Assert.AreEqual(2, employeeTran.Results.Count);
+ Assert.AreEqual(employee1.Name, employeeTran.Results[0].Name);
+ Assert.AreEqual(employee1.Version, employeeTran.Results[0].Version);
+ Assert.AreEqual(employee2.Name, employeeTran.Results[1].Name);
+ Assert.AreEqual(employee2.Version, employeeTran.Results[1].Version);
+ Assert.IsNotNull(productTran.Results);
+ Assert.AreEqual(1, productTran.Results.Count);
+ Assert.AreEqual(product.Id, productTran.Results[0].Id);
+ Assert.AreEqual(product.Version, productTran.Results[0].Version);
+ }
+
+ {
+ employee1.Score++;
+
+ var employeeTran = Context.CreateTransactWrite();
+ employeeTran.AddSaveItem(employee1);
+ employeeTran.AddDeleteItem(employee2);
+ var productTran = Context.CreateTransactWrite();
+ productTran.AddVersionCheckKey(product.Id, product.Version.Value + 1);
+ var tran = Context.CreateMultiTableTransactWrite(employeeTran, productTran);
+ var ex = AssertExtensions.ExpectException(() => tran.Execute());
+
+ Assert.IsNotNull(ex.CancellationReasons);
+ Assert.AreEqual(3, ex.CancellationReasons.Count);
+ Assert.AreEqual("None", ex.CancellationReasons[0].Code);
+ Assert.AreEqual("None", ex.CancellationReasons[1].Code);
+ Assert.AreEqual("ConditionalCheckFailed", ex.CancellationReasons[2].Code);
+
+ employee1.Score--;
+ }
+
+ {
+ var employeeTran = Context.CreateTransactGet();
+ employeeTran.AddKeys(new[] { employee1, employee2 });
+ var productTran = Context.CreateTransactGet();
+ productTran.AddKey(product);
+ var tran = Context.CreateMultiTableTransactGet(employeeTran, productTran);
+ tran.Execute();
+
+ Assert.IsNotNull(employeeTran.Results);
+ Assert.AreEqual(2, employeeTran.Results.Count);
+ Assert.AreEqual(employee1.Score, employeeTran.Results[0].Score);
+ Assert.AreEqual(employee1.Version, employeeTran.Results[0].Version);
+ Assert.AreEqual(employee2.Version, employeeTran.Results[1].Version);
+ Assert.IsNotNull(productTran.Results);
+ Assert.AreEqual(1, productTran.Results.Count);
+ Assert.AreEqual(product.Version, productTran.Results[0].Version);
+ }
+
+ {
+ var originalEmployeeVersion1 = employee1.Version.Value;
+ var originalEmployeeVersion2 = employee2.Version.Value;
+ var originalProductVersion = product.Version.Value;
+ employee1.Score++;
+ employee1.ManagerName = null;
+
+ var employeeTran = Context.CreateTransactWrite();
+ employeeTran.AddSaveItem(employee1);
+ employeeTran.AddDeleteItem(employee2);
+ var productTran = Context.CreateTransactWrite();
+ productTran.AddVersionCheckItem(product);
+ var tran = Context.CreateMultiTableTransactWrite(employeeTran, productTran);
+ tran.Execute();
+
+ Assert.AreEqual(originalEmployeeVersion1 + 1, employee1.Version);
+ Assert.AreEqual(originalEmployeeVersion2, employee2.Version);
+ Assert.AreEqual(originalProductVersion, product.Version);
+ }
+
+ {
+ var employeeTran = Context.CreateTransactGet();
+ employeeTran.AddKeys(new[] { employee1, employee2 });
+ var productTran = Context.CreateTransactGet();
+ productTran.AddKey(product.Id);
+ var tran = Context.CreateMultiTableTransactGet(employeeTran, productTran);
+ tran.Execute();
+
+ Assert.IsNotNull(employeeTran.Results);
+ Assert.AreEqual(1, employeeTran.Results.Count);
+ Assert.AreEqual(employee1.Name, employeeTran.Results[0].Name);
+ Assert.AreEqual(employee1.Score, employeeTran.Results[0].Score);
+ Assert.IsNull(employeeTran.Results[0].ManagerName);
+ Assert.AreEqual(employee1.Version, employeeTran.Results[0].Version);
+ Assert.IsNotNull(productTran.Results);
+ Assert.AreEqual(1, productTran.Results.Count);
+ Assert.AreEqual(product.Id, productTran.Results[0].Id);
+ Assert.AreEqual(product.Version, productTran.Results[0].Version);
+ }
+
+ {
+ var employeeTran = Context.CreateTransactWrite();
+ employeeTran.AddDeleteItem(employee1);
+ var productTran = Context.CreateTransactWrite();
+ productTran.AddDeleteKey(product.Id);
+ var tran = Context.CreateMultiTableTransactWrite(employeeTran, productTran);
+ tran.Execute();
+ }
+
+ {
+ var employeeTran = Context.CreateTransactGet();
+ employeeTran.AddKeys(new[] { employee1, employee2 });
+ var productTran = Context.CreateTransactGet();
+ productTran.AddKey(product);
+ var tran = Context.CreateMultiTableTransactGet(employeeTran, productTran);
+ tran.Execute();
+
+ Assert.IsNotNull(employeeTran.Results);
+ Assert.AreEqual(0, employeeTran.Results.Count);
+ Assert.IsNotNull(productTran.Results);
+ Assert.AreEqual(0, productTran.Results.Count);
+ }
+ }
+
private void TestOtherContextOperations()
{
Employee employee1 = new Employee
@@ -1976,6 +2423,22 @@ public class Employee3 : Employee
public EmptyType EmptyProperty { get; set; }
}
+ ///
+ /// Annotated class with a property of a type that has no valid constructor
+ ///
+ public class Employee4 : AnnotatedEmployee
+ {
+ public TimeSpan TimeWithCompany { get; set; }
+ }
+
+ ///
+ /// Annotated class with a property of an empty type
+ ///
+ public class Employee5 : AnnotatedEmployee
+ {
+ public EmptyType EmptyProperty { get; set; }
+ }
+
///
/// Empty type
///
@@ -1991,6 +2454,16 @@ public class VersionedEmployee : Employee
public int? Version { get; set; }
}
+ ///
+ /// Class representing items in the table [TableNamePrefix]HashTable
+ /// This class uses optimistic locking via the Version field
+ ///
+ public class VersionedAnnotatedEmployee : AnnotatedEmployee
+ {
+ [DynamoDBVersion]
+ public int? Version { get; set; }
+ }
+
///
/// Class representing items in the table [TableNamePrefix]HashTable
/// Two fields are being stored as epoch seconds, two are not.
@@ -2008,6 +2481,31 @@ public class EpochEmployee : Employee
public DateTime NonEpochDate2 { get; set; }
}
+ ///
+ /// Annotated class representing items in the table [TableNamePrefix]HashTable
+ /// Two fields are being stored as epoch seconds, two are not.
+ ///
+ [DynamoDBTable("NumericHashRangeTable")]
+ public class AnnotatedEpochEmployee
+ {
+ [DynamoDBRangeKey]
+ public string Name { get; set; }
+
+ public int Age { get; set; }
+
+ // Hash key
+ [DynamoDBHashKey(StoreAsEpoch = true)]
+ public virtual DateTime CreationTime { get; set; }
+
+ [DynamoDBProperty(StoreAsEpoch = true)]
+ public DateTime EpochDate2 { get; set; }
+
+ [DynamoDBProperty(StoreAsEpoch = false)]
+ public DateTime NonEpochDate1 { get; set; }
+
+ public DateTime NonEpochDate2 { get; set; }
+ }
+
///
/// Class representing items in the table [TableNamePrefix]NumericHashRangeTable.
///
@@ -2017,6 +2515,15 @@ public class NumericEpochEmployee : EpochEmployee
}
+ ///
+ /// Class representing items in the table [TableNamePrefix]NumericHashRangeTable.
+ ///
+ [DynamoDBTable("NumericHashRangeTable")]
+ public class AnnotatedNumEpochEmployee : AnnotatedEpochEmployee
+ {
+
+ }
+
///
/// Same structure as , but the Hash key is annotated
///
diff --git a/sdk/test/Services/DynamoDBv2/IntegrationTests/DocumentTests.cs b/sdk/test/Services/DynamoDBv2/IntegrationTests/DocumentTests.cs
index 86bad3e5ca89..9631ff8038d4 100644
--- a/sdk/test/Services/DynamoDBv2/IntegrationTests/DocumentTests.cs
+++ b/sdk/test/Services/DynamoDBv2/IntegrationTests/DocumentTests.cs
@@ -167,7 +167,9 @@ private void TestAsDateTimeUtc(Table numericHashRangeTable)
{
AttributesToStoreAsEpoch = new List { "CreationTime", "EpochDate2" }
};
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
var numericEpochTable = Table.LoadTable(Client, config);
+#pragma warning restore CS0618 // Re-enable the warning
// Capture current time
var currTime = DateTime.Now;
@@ -1816,9 +1818,13 @@ private void LoadTables(DynamoDBEntryConversion conversion, out Table hashTable,
{
// Load table using TryLoadTable API
hashTable = null;
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
Assert.IsFalse(Table.TryLoadTable(Client, "FakeHashTableThatShouldNotExist", conversion, true, out hashTable));
+#pragma warning restore CS0618 // Re-enable the warning
Assert.AreEqual(0, counter.ResponseCount);
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
Assert.IsTrue(Table.TryLoadTable(Client, hashTableName, conversion, true, out hashTable));
+#pragma warning restore CS0618 // Re-enable the warning
Assert.AreEqual(1, counter.ResponseCount);
Assert.IsNotNull(hashTable);
@@ -1832,10 +1838,14 @@ private void LoadTables(DynamoDBEntryConversion conversion, out Table hashTable,
Assert.AreEqual(0, hashTable.LocalSecondaryIndexes.Count);
Assert.AreEqual(0, hashTable.LocalSecondaryIndexNames.Count);
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
// Load table using LoadTable API (may throw an exception)
AssertExtensions.ExpectException(() => Table.LoadTable(Client, "FakeHashRangeTableThatShouldNotExist", conversion, true));
+#pragma warning restore CS0618 // Re-enable the warning
Assert.AreEqual(1, counter.ResponseCount);
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
hashRangeTable = Table.LoadTable(Client, hashRangeTableName, conversion, true);
+#pragma warning restore CS0618 // Re-enable the warning
Assert.AreEqual(2, counter.ResponseCount);
Assert.IsNotNull(hashRangeTable);
Assert.AreEqual(hashRangeTableName, hashRangeTable.TableName);
@@ -1849,7 +1859,9 @@ private void LoadTables(DynamoDBEntryConversion conversion, out Table hashTable,
Assert.AreEqual(2, hashRangeTable.LocalSecondaryIndexes["LocalIndex"].KeySchema.Count);
Assert.AreEqual(1, hashRangeTable.LocalSecondaryIndexNames.Count);
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
numericHashRangeTable = Table.LoadTable(Client, numericHashRangeTableName, conversion, true);
+#pragma warning restore CS0618 // Re-enable the warning
Assert.AreEqual(1, numericHashRangeTable.HashKeys.Count);
Assert.AreEqual(1, numericHashRangeTable.RangeKeys.Count);
Assert.AreEqual(2, numericHashRangeTable.Keys.Count);
diff --git a/sdk/test/Services/DynamoDBv2/IntegrationTests/DynamoDBTestsBase.cs b/sdk/test/Services/DynamoDBv2/IntegrationTests/DynamoDBTestsBase.cs
index 742411330d32..1380e87dfad5 100644
--- a/sdk/test/Services/DynamoDBv2/IntegrationTests/DynamoDBTestsBase.cs
+++ b/sdk/test/Services/DynamoDBv2/IntegrationTests/DynamoDBTestsBase.cs
@@ -92,14 +92,16 @@ public void CleanupTables()
public static void CreateContext(DynamoDBEntryConversion conversion, bool isEmptyStringValueEnabled, bool disableFetchingTableMetadata = false)
{
- var config = new DynamoDBContextConfig
- {
- //IgnoreNullValues = true
- IsEmptyStringValueEnabled = isEmptyStringValueEnabled,
- Conversion = conversion,
- DisableFetchingTableMetadata = disableFetchingTableMetadata
- };
- Context = new DynamoDBContext(Client, config);
+ Context = new DynamoDBContextBuilder()
+ .WithDynamoDBClient(() => Client)
+ .ConfigureContext(x =>
+ {
+ //x.IgnoreNullValues = true;
+ x.IsEmptyStringValueEnabled = isEmptyStringValueEnabled;
+ x.Conversion = conversion;
+ x.DisableFetchingTableMetadata = disableFetchingTableMetadata;
+ })
+ .Build();
}
public static string hashTableName;
@@ -126,7 +128,9 @@ public static void CreateContext(DynamoDBEntryConversion conversion, bool isEmpt
public static void ClearTable(string tableName)
{
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
var table = Table.LoadTable(Client, tableName, DynamoDBEntryConversion.V1, true);
+#pragma warning restore CS0618 // Re-enable the warning
var keyNames = table.Keys.Keys.ToList();
// Retrieve all keys
diff --git a/sdk/test/Services/DynamoDBv2/IntegrationTests/JSONTests.cs b/sdk/test/Services/DynamoDBv2/IntegrationTests/JSONTests.cs
index 70a2f0217757..a4d4b23dec6a 100644
--- a/sdk/test/Services/DynamoDBv2/IntegrationTests/JSONTests.cs
+++ b/sdk/test/Services/DynamoDBv2/IntegrationTests/JSONTests.cs
@@ -348,8 +348,7 @@ private static void TestFromJsonCanHandleAllDataTypes()
}
}";
- using (var dbClient = new AmazonDynamoDBClient())
- using (var context = new DynamoDBContext(dbClient))
+ using (var context = new DynamoDBContextBuilder().Build())
{
var document = Document.FromJson(json);
var container = context.FromDocument(document);
diff --git a/sdk/test/Services/DynamoDBv2/IntegrationTests/TTLTests.cs b/sdk/test/Services/DynamoDBv2/IntegrationTests/TTLTests.cs
index bfbef1f18d43..f92b023140a2 100644
--- a/sdk/test/Services/DynamoDBv2/IntegrationTests/TTLTests.cs
+++ b/sdk/test/Services/DynamoDBv2/IntegrationTests/TTLTests.cs
@@ -88,6 +88,66 @@ public void TestStoreAsEpoch()
Assert.IsNotNull(epochMap["NonEpochDate2"].S);
}
+ public void TestStoreAsAnnotatedEpoch()
+ {
+ var numericEmployee = new AnnotatedNumEpochEmployee
+ {
+ Name = "Bob",
+ Age = 45,
+ CreationTime = EpochDate,
+ EpochDate2 = EpochDate,
+ NonEpochDate1 = EpochDate,
+ NonEpochDate2 = EpochDate
+ };
+ AnnotatedEpochEmployee employee = numericEmployee;
+
+ Context.Save(employee);
+ var storedEmployee = Context.Load(employee.CreationTime, employee.Name);
+ Assert.IsNotNull(storedEmployee);
+ ApproximatelyEqual(EpochDate, storedEmployee.CreationTime);
+ storedEmployee = Context.Load(employee);
+ Assert.IsNotNull(storedEmployee);
+ ApproximatelyEqual(EpochDate, storedEmployee.CreationTime);
+
+
+ Context.Save(numericEmployee);
+ var storedNumericEmployee = Context.Load(employee.CreationTime, employee.Name);
+ Assert.IsNotNull(storedNumericEmployee);
+ ApproximatelyEqual(EpochDate, storedNumericEmployee.CreationTime);
+ storedNumericEmployee = Context.Load(numericEmployee);
+ Assert.IsNotNull(storedNumericEmployee);
+ ApproximatelyEqual(EpochDate, storedNumericEmployee.CreationTime);
+
+
+ var doc = Context.ToDocument(employee);
+ ApproximatelyEqual(EpochDate, doc["CreationTime"].AsDateTime());
+ ApproximatelyEqual(EpochDate, doc["EpochDate2"].AsDateTime());
+ ApproximatelyEqual(EpochDate, doc["NonEpochDate1"].AsDateTime());
+ ApproximatelyEqual(EpochDate, doc["NonEpochDate1"].AsDateTime());
+
+ var docV1 = doc.ForceConversion(DynamoDBEntryConversion.V1);
+ ApproximatelyEqual(EpochDate, docV1["CreationTime"].AsDateTime());
+ ApproximatelyEqual(EpochDate, docV1["EpochDate2"].AsDateTime());
+ ApproximatelyEqual(EpochDate, docV1["NonEpochDate1"].AsDateTime());
+ ApproximatelyEqual(EpochDate, docV1["NonEpochDate1"].AsDateTime());
+
+ var docV2 = doc.ForceConversion(DynamoDBEntryConversion.V1);
+ ApproximatelyEqual(EpochDate, docV2["CreationTime"].AsDateTime());
+ ApproximatelyEqual(EpochDate, docV2["EpochDate2"].AsDateTime());
+ ApproximatelyEqual(EpochDate, docV2["NonEpochDate1"].AsDateTime());
+ ApproximatelyEqual(EpochDate, docV2["NonEpochDate1"].AsDateTime());
+
+ var epochTable = Context.GetTargetTable();
+ var epochAttributes = epochTable.GetStoreAsEpoch().ToList();
+ Assert.AreNotEqual(0, epochAttributes.Count);
+
+ var epochMap = epochTable.ToAttributeMap(doc);
+ Assert.IsNotNull(epochMap["CreationTime"].N);
+ Assert.IsNotNull(epochMap["EpochDate2"].N);
+ Assert.IsNotNull(epochMap["NonEpochDate1"].S);
+ Assert.IsNotNull(epochMap["NonEpochDate2"].S);
+ }
+
public void TestStoreAsEpoch(Table hashRangeTable, Table numericHashRangeTable)
{
// verify conversions
@@ -106,14 +166,18 @@ public void TestStoreAsEpoch(Table hashRangeTable, Table numericHashRangeTable)
{
AttributesToStoreAsEpoch = new List { "CreationTime", "EpochDate2" }
};
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
var epochTable = Table.LoadTable(Client, config);
+#pragma warning restore CS0618 // Re-enable the warning
CollectionAssert.AreEqual(config.AttributesToStoreAsEpoch, epochTable.GetStoreAsEpoch().ToList());
config = new TableConfig(numericHashRangeTable.TableName)
{
AttributesToStoreAsEpoch = new List { "CreationTime", "EpochDate2" }
};
+#pragma warning disable CS0618 // Disable the warning for the deprecated DynamoDBContext constructors
var numericEpochTable = Table.LoadTable(Client, config);
+#pragma warning restore CS0618 // Re-enable the warning
CollectionAssert.AreEqual(config.AttributesToStoreAsEpoch, epochTable.GetStoreAsEpoch().ToList());
// verify ToAttributeMap calls