使用 Amazon DynamoDB NoSQL 数据库 - Amazon SDK for .NET
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用 Amazon DynamoDB NoSQL 数据库

注意

这些主题中的编程模型同时存在于 .NET Framework 和 .NET (Core) 中,但是调用约定不同,无论是同步还是异步。

Amazon SDK for .NET支持 Amazon DynamoDB,这是一项由 Amazon 提供的快速 NoSQL 数据库服务。开发工具包为与 DynamoDB 通信提供了三种编程模型:低级模型、文档模型和对象持久性模型。

以下信息介绍了这些模型及其 API,提供有关使用方式和使用时机的示例,并向您提供Amazon SDK for .NET中额外 DynamoDB 编程资源的链接。

低级模型

低级编程模型封装对 DynamoDB 服务的直接调用。您可以通过 Amazon.DynamoDBv2 命名空间访问此模型。

在三种模型中,低级模型需要编写的代码最多。例如,您必须将 .NET 数据类型转换为 DynamoDB 中的对等类型。但是,此模型向您提供了对大部分功能的访问。

以下示例显示如何使用低级模型创建表、修改表以及将项目插入到 DynamoDB 中的表。

创建表

在以下示例中,您可以使用 CreateTable 类的 AmazonDynamoDBClient 方法创建表。CreateTable 方法使用包含特性的 CreateTableRequest 类的实例,例如必需的项目属性名称、主键定义和吞吐容量。该 CreateTable 方法返回 CreateTableResponse 类的实例。

// using Amazon.DynamoDBv2; // using Amazon.DynamoDBv2.Model; var client = new AmazonDynamoDBClient(); Console.WriteLine("Getting list of tables"); List<string> currentTables = client.ListTables().TableNames; Console.WriteLine("Number of tables: " + currentTables.Count); if (!currentTables.Contains("AnimalsInventory")) { var request = new CreateTableRequest { TableName = "AnimalsInventory", AttributeDefinitions = new List<AttributeDefinition> { new AttributeDefinition { AttributeName = "Id", // "S" = string, "N" = number, and so on. AttributeType = "N" }, new AttributeDefinition { AttributeName = "Type", AttributeType = "S" } }, KeySchema = new List<KeySchemaElement> { new KeySchemaElement { AttributeName = "Id", // "HASH" = hash key, "RANGE" = range key. KeyType = "HASH" }, new KeySchemaElement { AttributeName = "Type", KeyType = "RANGE" }, }, ProvisionedThroughput = new ProvisionedThroughput { ReadCapacityUnits = 10, WriteCapacityUnits = 5 }, }; var response = client.CreateTable(request); Console.WriteLine("Table created with request ID: " + response.ResponseMetadata.RequestId); }

验证该表已准备好修改

您必须先准备好表进行修改,然后才能更改或修改表。以下示例显示了如何使用低级模型验证 DynamoDB 中的表已准备就绪。在此示例中,通过 DescribeTable 类的 AmazonDynamoDBClient 方法引用要检查的目标表。该代码每五秒检查一次表的 TableStatus 属性的值。当状态设置为 ACTIVE 时,表已准备好供修改。

// using Amazon.DynamoDBv2; // using Amazon.DynamoDBv2.Model; var client = new AmazonDynamoDBClient(); var status = ""; do { // Wait 5 seconds before checking (again). System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); try { var response = client.DescribeTable(new DescribeTableRequest { TableName = "AnimalsInventory" }); Console.WriteLine("Table = {0}, Status = {1}", response.Table.TableName, response.Table.TableStatus); status = response.Table.TableStatus; } catch (ResourceNotFoundException) { // DescribeTable is eventually consistent. So you might // get resource not found. } } while (status != TableStatus.ACTIVE);

将项目插入到表中

在以下示例中,您使用低级模型将两个项目插入到 DynamoDB 中的表。每个项目通过 PutItem 类的 AmazonDynamoDBClient 方法插入,使用 PutItemRequest 类的实例。PutItemRequest 类的两个实例中的每个实例都接受将要插入项目的表名以及一系列项目属性值。

// using Amazon.DynamoDBv2; // using Amazon.DynamoDBv2.Model; var client = new AmazonDynamoDBClient(); var request1 = new PutItemRequest { TableName = "AnimalsInventory", Item = new Dictionary<string, AttributeValue> { { "Id", new AttributeValue { N = "1" }}, { "Type", new AttributeValue { S = "Dog" }}, { "Name", new AttributeValue { S = "Fido" }} } }; var request2 = new PutItemRequest { TableName = "AnimalsInventory", Item = new Dictionary<string, AttributeValue> { { "Id", new AttributeValue { N = "2" }}, { "Type", new AttributeValue { S = "Cat" }}, { "Name", new AttributeValue { S = "Patches" }} } }; client.PutItem(request1); client.PutItem(request2);

文档模型

文档编程模型提供了一种更简单的方法来处理 DynamoDB 中的数据。此模型专门用于访问表和表中的项目。您可以通过 Amazon.DynamoDBv2.DocumentModel 命名空间访问此模型。

与低级编程模型相比,使用文档模型更容易针对 DynamoDB 数据编写代码。例如,您无需将相同数量的 .NET 数据类型转换为 DynamoDB 中的对等类型。不过,使用此模型所能访问的功能没有低级编程模型所提供的多。例如,您可以使用此模型创建、检索、更新和删除表中的项目。但是,要创建表,您必须使用低级模型。与对象持久化模型相比,此模型需要编写更多代码来存储、加载和查询 .NET 对象。

有关 DynamoDB 文档编程模型的更多信息,请参阅 Amazon DynamoDB 开发人员指南中的 .NET:文档模型

以下各节提供有关如何创建所需的 DynamoDB 表的表示形式的信息,以及如何使用文档模型将项目插入表和从表中获取项目的示例。

创建表的表示形式

要使用文档模型执行数据操作,您必须首先创建 Table 类的实例,它会代表特定的表。有两种主要方式可执行此操作:

LoadTable 方法

第一种机制是使用 Table 类的静态 LoadTable 方法之一,类似于以下示例:

var client = new AmazonDynamoDBClient(); Table table = Table.LoadTable(client, "Reply");
注意

虽然这种机制起作用,但在某些条件下,由于冷启动和线程池行为,它有时会导致额外的延迟或死锁。有关这些行为的更多信息,请参阅博客文章 Improved DynamoDB Initialization Patterns for the Amazon SDK for .NET

TableBuilder

AWSSDK.DynamoDBv2 NuGet 程序包的 3.7.203 版本中引入了另一种机制,即 TableBuilder类。该机制可以通过删除某些隐式方法调用(特别是 DescribeTable 方法)来解决上述行为。此机制的使用方式类似于以下示例:

var client = new AmazonDynamoDBClient(); var table = new TableBuilder(client, "Reply") .AddHashKey("Id", DynamoDBEntryType.String) .AddRangeKey("ReplyDateTime", DynamoDBEntryType.String) .AddGlobalSecondaryIndex("PostedBy-Message-index", "Author", DynamoDBEntryType.String, "Message", DynamoDBEntryType.String) .Build();

有关此替代机制的更多信息,请再次参阅博客文章 Improved DynamoDB Initialization Patterns for the Amazon SDK for .NET

将项目插入到表中

在以下示例中,回复通过 Table 类的 PutItemAsync 方法插入到 Reply 表中。PutItemAsync 方法获取 Document 类的实例;Document 类只是已初始化属性的集合。

using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.DocumentModel; // Create a representation of the "Reply" table // by using one of the mechanisms described previously. // Then, add a reply to the table. var newReply = new Document(); newReply["Id"] = Guid.NewGuid().ToString(); newReply["ReplyDateTime"] = DateTime.UtcNow; newReply["PostedBy"] = "Author1"; newReply["Message"] = "Thank you!"; await table.PutItemAsync(newReply);

从表中获取项目

在以下示例中,通过 Table 类的 GetItemAsync 方法检索回复。为确定要获取的回复,GetItemAsync 方法使用目标回复的 hash-and-range 主键。

using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.DocumentModel; // Create a representation of the "Reply" table // by using one of the mechanisms described previously. // Then, get a reply from the table // where "guid" is the hash key and "datetime" is the range key. var reply = await table.GetItemAsync(guid, datetime); Console.WriteLine("Id = " + reply["Id"]); Console.WriteLine("ReplyDateTime = " + reply["ReplyDateTime"]); Console.WriteLine("PostedBy = " + reply["PostedBy"]); Console.WriteLine("Message = " + reply["Message"]);

前面的示例为 WriteLine 方法隐式将表值转换为字符串。您可以使用 DynamoDBEntry 类的多种“As[type]”方法执行显式转换。例如,对于 Id 的值,您可以通过 AsGuid() 方法将其从 Primitive 数据类型显式转换为 GUID:

var guid = reply["Id"].AsGuid();

对象持久化模型

对象持久性编程模型专门针对在 DynamoDB 中存储、加载和查询 .NET 对象而设计。您可以通过 Amazon.DynamoDBv2.DataModel 命名空间访问此模型。

在三种模型中,使用对象持久性模型最容易针对要存储、加载或查询的 DynamoDB 数据编写代码。例如,您可以直接使用 DynamoDB 数据类型。但是,此模型仅支持在 DynamoDB 中存储、加载和查询 .NET 对象的操作。例如,您可以使用此模型创建、检索、更新和删除表中的项目。不过,您必须先使用低级模型创建表,然后使用此模型将 .NET 类映射到表。

有关 DynamoDB 对象持久性编程模型的更多信息,请参阅 Amazon DynamoDB 开发人员指南中的 .NET:对象持久性模型

以下示例向您演示如何定义表示 DynamoDB 项目的 .NET 类,使用 .NET 类的实例将项目插入到 DynamoDB ,以及使用 .NET 对象的实例从表获取项目。

定义表示表中项目的 .NET 类

在以下类定义示例中,DynamoDBTable 属性指定表名,而 DynamoDBHashKeyDynamoDBRangeKey 属性对表的 hash-and-range 主键进行建模。定义 DynamoDBGlobalSecondaryIndexHashKey 属性的目的是为了可以构造对特定作者回复的查询。

using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.DataModel; [DynamoDBTable("Reply")] public class Reply { [DynamoDBHashKey] public string Id { get; set; } [DynamoDBRangeKey(StoreAsEpoch = false)] public DateTime ReplyDateTime { get; set; } [DynamoDBGlobalSecondaryIndexHashKey("PostedBy-Message-Index", AttributeName ="PostedBy")] public string Author { get; set; } [DynamoDBGlobalSecondaryIndexRangeKey("PostedBy-Message-Index")] public string Message { get; set; } }

为对象持久性模型创建上下文

要使用适用于 DynamoDB 的对象持久性编程模型,您需要创建一个上下文,它提供到 DynamoDB 的连接,让您能够访问表、执行各种操作,以及执行查询。

基本上下文

以下代码示例演示如何创建最基本的上下文 。

using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.DataModel; var client = new AmazonDynamoDBClient(); var context = new DynamoDBContext(client);

具有 DisableFetchingTableMetadata 属性的上下文

以下示例显示了如何额外设置 DynamoDBContextConfig 类的 DisableFetchingTableMetadata 属性以防止隐式调用 DescribeTable 方法。

using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.DataModel; var client = new AmazonDynamoDBClient(); var context = new DynamoDBContext(client, new DynamoDBContextConfig { DisableFetchingTableMetadata = true });

如果将该 DisableFetchingTableMetadata 属性设置为 false(默认值),如第一个示例所示,则可以省略 Reply 类中描述表项键和索引结构的属性。相反,这些属性将通过对 DescribeTable 方法的隐式调用推断出来。如第二个示例所示,如果 DisableFetchingTableMetadata 设置为 true,则对象持久性模型的方法(例如 SaveAsyncQueryAsync)完全依赖于 Reply 类中定义的属性。在这种情况下,不会调用 DescribeTable 方法。

注意

在某些情况下,由于冷启动和线程池行为,对 DescribeTable 方法的调用有时会导致额外的延迟或死锁。因此,有时避免调用该方法是有利的。

有关这些行为的更多信息,请参阅博客文章 Improved DynamoDB Initialization Patterns for the Amazon SDK for .NET

使用 .NET 类的实例将项目插入到表中

在本示例中,项目通过 SaveAsync 类的 DynamoDBContext 方法插入,该方法采用表示项目的 .NET 类的已初始化实例。

using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.DataModel; // Create an appropriate context for the object persistence programming model, // examples of which have been described earlier. // Create an object that represents the new item. var reply = new Reply() { Id = Guid.NewGuid().ToString(), ReplyDateTime = DateTime.UtcNow, Author = "Author1", Message = "Thank you!" }; // Insert the item into the table. await context.SaveAsync<Reply>(reply, new DynamoDBOperationConfig { IndexName = "PostedBy-Message-index" });

使用 .NET 类的实例从表中获取项目

在此示例中,使用 DynamoDBContext 类的 QueryAsync 方法创建了一个查询,用于查找“Author1”的所有记录。然后,通过查询的 GetNextSetAsync 方法检索项目。

using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.DataModel; // Create an appropriate context for the object persistence programming model, // examples of which have been described earlier. // Construct a query that finds all replies by a specific author. var query = context.QueryAsync<Reply>("Author1", new DynamoDBOperationConfig { IndexName = "PostedBy-Message-index" }); // Display the result. var set = await query.GetNextSetAsync(); foreach (var item in set) { Console.WriteLine("Id = " + item.Id); Console.WriteLine("ReplyDateTime = " + item.ReplyDateTime); Console.WriteLine("PostedBy = " + item.Author); Console.WriteLine("Message = " + item.Message); }

有关对象持久性模型的其它信息

上面显示的示例和解释有时包括名为 DisableFetchingTableMetadataDynamoDBContext 类的属性。此属性在 AWSSDK.DynamoDBv2 NuGet 程序包的 3.7.203 版本中引入,允许您避免某些可能由于冷启动和线程池行为而导致额外延迟或死锁的情况。有关更多信息,请参阅博客文章 Improved DynamoDB Initialization Patterns for the Amazon SDK for .NET

以下是有关此属性的一些其它信息。

  • 如果您使用.NET Framework,则可以在 app.configweb.config 文件中全局设置此属性。

  • 可以使用 AWSConfigsDynamoDB 类全局设置此属性,如下面的示例所示。

    // Set the DisableFetchingTableMetadata property globally // before constructing any context objects. AWSConfigsDynamoDB.Context.DisableFetchingTableMetadata = true; var client = new AmazonDynamoDBClient(); var context = new DynamoDBContext(client);
  • 在某些情况下,您无法将 DynamoDB 属性添加到 .NET 类中;例如,如果该类是在依赖项中定义的。在这种情况下,仍然可以利用 DisableFetchingTableMetadata 属性。为此,除了 DisableFetchingTableMetadata 属性之外,还要使用 TableBuilder 类。在 AWSSDK.DynamoDBv2 NuGet 程序包的 3.7.203 版本中引入了 TableBuilder 类。

    // Set the DisableFetchingTableMetadata property globally // before constructing any context objects. AWSConfigsDynamoDB.Context.DisableFetchingTableMetadata = true; var client = new AmazonDynamoDBClient(); var context = new DynamoDBContext(client); var table = new TableBuilder(client, "Reply") .AddHashKey("Id", DynamoDBEntryType.String) .AddRangeKey("ReplyDateTime", DynamoDBEntryType.String) .AddGlobalSecondaryIndex("PostedBy-Message-index", "Author", DynamoDBEntryType.String, "Message", DynamoDBEntryType.String) .Build(); // This registers the "Reply" table we constructed via the builder. context.RegisterTableDefinition(table); // Now operations like this will work, // even if the Reply class was not annotated with this index. var query = context.QueryAsync<Reply>("Author1", new DynamoDBOperationConfig() { IndexName = "PostedBy-Message-index" });

更多信息

使用Amazon SDK for .NET编程 DynamoDB 信息和示例**

低级模型信息和示例

文档模型信息和示例

对象持久性模型信息和示例