

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 DynamoDB Mapper 將類別映射至 DynamoDB 項目 （開發人員預覽版）
<a name="ddb-mapper"></a>

****  
**DynamoDB Mapper 是開發人員預覽版本。其功能不完整，可能會有所變更。**

DynamoDB Mapper 是一個高階程式庫，提供將 Kotlin 類別映射至 DynamoDB 資料表和索引的機制，類似於 適用於 Java 的 AWS SDK的 [DynamoDB 增強型用戶端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html)或 適用於 .NET 的 AWS SDK的[物件持久性模型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKHighLevel.html)。

您可以定義描述資料物件的結構描述，以及如何將其轉換為 DynamoDB 項目。定義結構描述後，DynamoDB Mapper 會提供直覺式界面，在資料表和索引的建立、讀取、更新或刪除 (CRUD) 操作中使用您的物件。

**Topics**
+ [DynamoDB Mapper 入門](ddb-mapper-get-started.md)
+ [設定 DynamoDB Mapper](ddb-mapper-configuration.md)
+ [從註釋產生結構描述](ddb-mapper-anno-schema-gen.md)
+ [手動定義結構描述](ddb-mapper-code-schemas.md)
+ [搭配 DynamoDB Mapper 使用次要索引](ddb-mapper-secondary-indices.md)
+ [使用表達式](ddb-mapper-expressions.md)

# DynamoDB Mapper 入門
<a name="ddb-mapper-get-started"></a>

****  
**DynamoDB Mapper 是開發人員預覽版本。其功能不完整，可能會有所變更。**

下列教學課程介紹 DynamoDB Mapper 的基本元件，並說明如何在程式碼中使用它。

## 新增相依性
<a name="ddb-mapper-get-started-deps"></a>

若要開始在 Gradle 專案中使用 DynamoDB Mapper，請將外掛程式和兩個相依性新增至 `build.gradle.kts` 檔案。

（您可以導覽至 *X.Y.Z* 連結，以查看可用的最新版本。)

```
// build.gradle.kts
val sdkVersion: String = [https://github.com/awslabs/aws-sdk-kotlin/releases/latest](https://github.com/awslabs/aws-sdk-kotlin/releases/latest)

plugins {
    id("aws.sdk.kotlin.hll.dynamodbmapper.schema.generator") version "$sdkVersion-beta" // For the Developer Preview, use the beta version of the latest SDK.
}

dependencies {
    implementation("aws.sdk.kotlin:dynamodb-mapper:$sdkVersion-beta")
    implementation("aws.sdk.kotlin:dynamodb-mapper-annotations:$sdkVersion-beta")
}
```

\$1將 *<Version>* 取代為最新版本的 SDK。若要尋找最新版本的 SDK，請檢查 [ GitHub 上的最新版本](https://github.com/awslabs/aws-sdk-kotlin/releases/latest)。

**注意**  
如果您打算手動定義結構描述，其中一些相依性是選用的。[手動定義結構描述](ddb-mapper-code-schemas.md) 如需詳細資訊和減少的相依性集，請參閱 。

## 建立和使用映射器
<a name="ddb-mapper-get-started-mapper"></a>

DynamoDB Mapper 使用 適用於 Kotlin 的 AWS SDK的 DynamoDB 用戶端與 DynamoDB 互動。當您建立映射器[https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb/aws.sdk.kotlin.services.dynamodb/-dynamo-db-client/index.html](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb/aws.sdk.kotlin.services.dynamodb/-dynamo-db-client/index.html)執行個體時，您需要提供完全設定的執行個體，如下列程式碼片段所示：

```
import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbMapper
import aws.sdk.kotlin.services.dynamodb.DynamoDbClient

val client = DynamoDbClient.fromEnvironment()
val mapper = DynamoDbMapper(client)
```

**注意**  
`DynamoDbMapper` 不支援資料表建立操作。使用 `DynamoDbClient`建立資料表。

建立映射器執行個體之後，您可以使用它來取得資料表執行個體，如下所示：

```
val carsTable = mapper.getTable("cars", CarSchema)
```

先前的程式碼會使用 定義的結構描述，取得 中`DynamoDB`名為 `cars` 之資料表的參考 `CarSchema`（我們將在下面討論結構描述）。建立資料表執行個體之後，您可以對其執行操作。下列程式碼片段顯示`cars`資料表的兩個範例操作：

```
carsTable.putItem {
    item = Car(make = "Ford", model = "Model T", ...)
}

carsTable
   .queryPaginated {
        keyCondition = KeyFilter(partitionKey = "Peugeot")
   }
   .items()
   .collect { car -> println(car) }
```

先前的程式碼會在`cars`資料表中建立新的項目。此程式碼會使用 `Car`類別內嵌建立`Car`執行個體，其定義如下所示。接下來，程式碼會查詢`cars`資料表中分割區索引鍵為 的項目，`Peugeot`並列印它們。操作[的詳細說明如下](#ddb-mapper-gs-invoke-ops)。

## 使用類別註釋定義結構描述
<a name="ddb-mapper-gs-anno-schema-def"></a>

對於各種 Kotlin 類別，開發套件可以使用適用於 Gradle 的 DynamoDB Mapper 結構描述產生器外掛程式，在建置時間自動產生結構描述。當您使用結構描述產生器時，軟體開發套件會檢查您的類別來推斷結構描述，這會緩解手動定義結構描述時涉及的一些樣板。您可以使用其他[註釋](ddb-mapper-anno-schema-gen.md#ddb-mapper-anno-schema-gen-annotate)和[組態](ddb-mapper-anno-schema-gen.md#ddb-mapper-anno-schema-gen-conf-plugin)來自訂產生的結構描述。

若要從註釋產生結構描述，請先使用 註釋您的類別，並使用 `@[DynamoDbItem](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-item/index.html)` 和 `@[DynamoDbPartitionKey](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-partition-key/index.html)` 註釋任何索引鍵`@[DynamoDbSortKey](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-sort-key/index.html)`。下列程式碼顯示註釋的`Car`類別：

```
// The annotations used in the Car class are used by the plugin to generate a schema.
@DynamoDbItem
data class Car(
    @DynamoDbPartitionKey
    val make: String,
    
    @DynamoDbSortKey
    val model: String,
    
    val initialYear: Int
)
```

建置之後，您可以參考自動產生的 `CarSchema`。您可以使用映射器`getTable`方法中的 參考來取得資料表執行個體，如下所示：

```
import aws.sdk.kotlin.hll.dynamodbmapper.generatedschemas.CarSchema

// `CarSchema` is generated at build time.
val carsTable = mapper.getTable("cars", CarSchema)
```

或者，您可以利用建置時`[DynamoDbMapper](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-mapper/index.html)`自動產生的 延伸方法來取得資料表執行個體。透過使用此方法，您不需要依名稱參考結構描述。如下所示，自動產生的`getCarsTable`延伸方法會傳回資料表執行個體的參考：

```
val carsTable = mapper.getCarsTable("cars")
```

如需詳細資訊和範例，請參閱 [從註釋產生結構描述](ddb-mapper-anno-schema-gen.md)。

## 叫用 操作
<a name="ddb-mapper-gs-invoke-ops"></a>

DynamoDB Mapper 支援開發套件 上可用操作的子集`DynamoDbClient`。Mapper 操作的名稱與 SDK 用戶端上的對應操作相同。許多映射器請求/回應成員與其 SDK 用戶端相同，但有些已重新命名、重新輸入或捨棄。

您可以使用 DSL 語法在資料表執行個體上叫用 操作，如下所示：

```
import aws.sdk.kotlin.hll.dynamodbmapper.operations.putItem
import aws.sdk.kotlin.services.dynamodb.model.ReturnConsumedCapacity

val putResponse = carsTable.putItem {
    item = Car(make = "Ford", model = "Model T", ...)
    returnConsumedCapacity = ReturnConsumedCapacity.Total
}

println(putResponse.consumedCapacity)
```

您也可以使用明確請求物件叫用 操作：

```
import aws.sdk.kotlin.hll.dynamodbmapper.operations.PutItemRequest
import aws.sdk.kotlin.services.dynamodb.model.ReturnConsumedCapacity

val putRequest = PutItemRequest<Car> {
    item = Car(make = "Ford", model = "Model T", ...)
    returnConsumedCapacity = ReturnConsumedCapacity.Total
}

val putResponse = carsTable.putItem(putRequest)
println(putResponse.consumedCapacity)
```

前兩個程式碼範例是相等的。

### 使用分頁回應
<a name="ddb-mapper-gs-pagination"></a>

有些操作，例如 `query`和 `scan`可以傳回可能太大而無法在單一回應中傳回的資料收集。為了確保處理所有物件，DynamoDB Mapper 提供分頁方法，不會立即呼叫 DynamoDB，而是傳回`[Flow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/)`操作回應類型的 ，如下所示`Flow<ScanResponse<Car>>`：

```
import aws.sdk.kotlin.hll.dynamodbmapper.operations.scanPaginated

val scanResponseFlow = carsTable.scanPaginated { }

scanResponseFlow.collect { response ->
    val items = response.items.orEmpty()
    println("Found page with ${items.size} items:")
    
    items.forEach { car -> println(car) }
}
```

通常，物件流程對於商業邏輯比*包含*物件的回應流程更有用。映射器提供分頁回應的延伸方法，以存取物件的流程。例如，下列程式碼會傳回 `Flow<Car>`而非 `Flow<ScanResponse<Car>>`，如先前所示：

```
import aws.sdk.kotlin.hll.dynamodbmapper.operations.items
import aws.sdk.kotlin.hll.dynamodbmapper.operations.scanPaginated

val carFlow = carsTable
    .scanPaginated { }
    .items()

carFlow.collect { car -> println(car) }
```

# 設定 DynamoDB Mapper
<a name="ddb-mapper-configuration"></a>

****  
**DynamoDB Mapper 是開發人員預覽版本。其功能不完整，可能會有所變更。**

DynamoDB Mapper 提供組態選項，您可以使用自訂程式庫的行為以符合您的應用程式。

## 使用攔截器
<a name="ddb-mapper-interceptors"></a>

DynamoDB Mapper 程式庫定義您可以在映射器請求管道的關鍵階段使用掛鉤。您可以實作`[Interceptor](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.pipeline/-interceptor/index.html)`界面來實作勾點，以觀察或修改映射器程序。

您可以將單一 DynamoDB Mapper 上的一或多個攔截器註冊為組態選項。如需如何註冊攔截器，請參閱本節結尾[的範例](#ddb-mapper-interceptors-hooks-example-conf)。

### 了解請求管道
<a name="ddb-mapper-interceptors-pipeline"></a>

映射器的請求管道包含下列 5 個步驟：

1. **初始化：**設定 操作並收集初始內容。

1. **序列化：**將高階請求物件轉換為低階請求物件。此步驟會將高階 Kotlin 物件轉換為由屬性名稱和值組成的 DynamoDB 項目。

1. **低階調用：**在基礎 DynamoDB 用戶端上執行請求。

1. **去序列化：**將低階回應物件轉換為高階回應物件。此步驟包含將包含屬性名稱和值的 DynamoDB 項目轉換為高階 Kotlin 物件。

1. **完成：**完成高階回應以傳回給發起人。如果在管道執行期間擲回例外狀況，此步驟會完成擲回給發起人的例外狀況。

### 勾點
<a name="ddb-mapper-interceptors-hooks"></a>

勾點是映射器在管道中特定步驟之前或之後調用的攔截器方法。勾點有兩種變體：*唯讀*和*修改* （或讀寫）。例如， `readBeforeInvocation` 是唯讀勾點，映射器會在低階調用步驟之前在 階段中執行。

#### 唯讀勾點
<a name="ddb-mapper-interceptors-hooks-ro"></a>

映射器會在管道中每個步驟之前和之後叫用唯讀勾點 (*初始化*步驟之前和*完成*步驟之後除外）。唯讀機罩提供正在進行的高階操作的唯讀檢視。它們提供一種機制來檢查 操作的狀態，例如記錄、偵錯、收集指標。每個唯讀勾點都會接收內容引數，並傳回 `[Unit](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/)`。

映射器會擷取在唯讀勾點期間擲回的任何例外狀況，並將其新增至內容。然後，它會將具有例外狀況的內容傳遞至相同階段中的後續攔截器勾點。映射器只會在呼叫最後一個攔截器相同階段的唯讀勾點之後，才會將任何例外狀況擲回給發起人。例如，如果映射器設定了兩個攔截器`A`和 `B`，而 `A`的`readAfterSerialization`勾點擲回例外狀況，映射器會將例外狀況新增至傳遞至 `B`勾`readAfterSerialization`點的內容。`B`的`readAfterSerialization`勾點完成後，映射器會將例外狀況擲回給發起人。

#### 修改掛鉤
<a name="ddb-mapper-interceptors-hooks-modify"></a>

映射器會在管道中的每個步驟之前叫用修改掛鉤 (*初始化*之前除外）。修改掛鉤可讓您查看和修改正在進行的高階操作。它們可用來以映射器組態和項目結構描述未採用的方式自訂行為和資料。每個修改勾點都會收到內容引數，並因此傳回該內容的一些子集 - 由勾點修改或從輸入內容傳遞。

如果映射器在執行修改勾點時擷取任何例外狀況，則不會在相同階段執行任何其他攔截器的修改勾點。映射器會將例外狀況新增至內容，並將其傳遞至下一個唯讀勾點。映射器只會在呼叫最後一個攔截者的相同階段唯讀勾點之後，才會將任何例外狀況擲回給發起人。例如，如果映射器設定了兩個攔截器`A`和 `B`，而 `A`的`modifyBeforeSerialization`勾點擲回例外狀況，則不會叫用 `B`的`modifyBeforeSerialization`勾點。將執行攔截器 `A`和 `B'`s `readAfterSerialization` hook，之後會將例外狀況擲回給發起人。

#### 執行順序
<a name="ddb-mapper-interceptors-hooks-ex-order"></a>

在映射器的組態中定義攔截器的順序決定映射器呼叫勾點的順序：
+ 對於*低階調用*步驟*之前的*階段，它會以其在組態中新增的*相同順序*執行掛鉤。
+ 對於*低階調用*步驟*之後*的階段，它會以與組態中新增的順序*相反的順序*執行勾點。

下圖顯示勾點方法的執行順序：

![\[攔截器勾點方法的流程圖。\]](http://docs.aws.amazon.com/zh_tw/sdk-for-kotlin/latest/developer-guide/images/KotlinDevGuide-dynamodbMapper-hook-flowchart.png)


##### 勾點方法執行順序的文字描述
<a name="ixg_ypr_ddc"></a>

映射器會依下列順序執行攔截器的勾點：

1. DynamoDB Mapper 調用高階請求

1. 執行前讀取

1. 在序列化之前修改

1. 序列化前讀取

1. DynamoDB Mapper 會將物件轉換為項目

1. 序列化後讀取

1. 叫用前修改

1. 叫用前讀取

1. DynamoDB Mapper 調用低階操作

1. 叫用後讀取

1. 在還原序列化之前修改

1. 還原序列化前讀取

1. DynamoDB Mapper 會將項目轉換為物件

1. 還原序列化後讀取

1. 完成前修改

1. 執行後讀取

1. DynamoDB Mapper 傳回高階回應

#### 範例組態
<a name="ddb-mapper-interceptors-hooks-example-conf"></a>

下列範例示範如何在`DynamoDbMapper`執行個體上設定攔截器：

```
import aws.sdk.kotlin.hll.dynamodbmapper.DynamoDbMapper
import aws.sdk.kotlin.hll.dynamodbmapper.operations.ScanRequest
import aws.sdk.kotlin.hll.dynamodbmapper.operations.ScanResponse
import aws.sdk.kotlin.hll.dynamodbmapper.pipeline.Interceptor
import aws.sdk.kotlin.services.dynamodb.DynamoDbClient
import aws.sdk.kotlin.services.dynamodb.model.ScanRequest as LowLevelScanRequest
import aws.sdk.kotlin.services.dynamodb.model.ScanResponse as LowLevelScanResponse

val printingInterceptor = object : Interceptor<User, ScanRequest<User>, LowLevelScanRequest, LowLevelScanResponse, ScanResponse<User>> {
    override fun readBeforeDeserialization(ctx: LResContext<User, ScanRequest<User>, LowLevelScanRequest, LowLevelScanResponse>) {
        println("Scan response contains ${ctx.lowLevelResponse.count} items.")
    }
}

val client = DynamoDbClient.fromEnvironment()

val mapper = DynamoDbMapper(client) {
    interceptors += printingInterceptor
}
```

# 從註釋產生結構描述
<a name="ddb-mapper-anno-schema-gen"></a>

****  
**DynamoDB Mapper 是開發人員預覽版本。其功能不完整，可能會有所變更。**

DynamoDB Mapper 依賴於定義 Kotlin 類別與 DynamoDB 項目之間映射的結構描述。您的 Kotlin 類別可以使用結構描述產生器 Gradle 外掛程式來推動結構描述的建立。

## 套用外掛程式
<a name="ddb-mapper-anno-schema-gen-plugin"></a>

若要開始為您的類別產生程式碼結構描述，請在應用程式的建置指令碼中套用外掛程式，並在註釋模組上新增相依性。下列 Gradle 指令碼程式碼片段顯示產生程式碼所需的設定。

（您可以導覽至 *X.Y.Z* 連結，以查看可用的最新版本。)

```
// build.gradle.kts
val sdkVersion: String = [https://github.com/awslabs/aws-sdk-kotlin/releases/latest](https://github.com/awslabs/aws-sdk-kotlin/releases/latest) 

plugins {
    id("aws.sdk.kotlin.hll.dynamodbmapper.schema.generator") version "$sdkVersion-beta" // For the Developer Preview, use the beta version of the latest SDK.
}

dependencies {
    implementation("aws.sdk.kotlin:dynamodb-mapper:$sdkVersion-beta")
    implementation("aws.sdk.kotlin:dynamodb-mapper-annotations:$sdkVersion-beta")
}
```

## 設定 外掛程式
<a name="ddb-mapper-anno-schema-gen-conf-plugin"></a>

外掛程式提供許多組態選項，您可以使用建置指令碼中的`dynamoDbMapper { ... }`外掛程式延伸來套用：


| 選項 | 選項描述 | 值 | 
| --- | --- | --- | 
| generateBuilderClasses |  控制是否為標註 的類別產生 DSL 樣式建置器類別 `@DynamoDbItem`  |  `WHEN_REQUIRED` （預設）：不會對僅包含公有可變成員且具有零位元建構函數的類別產生建置器類別 `ALWAYS`：一律會產生建置器類別  | 
| visibility | 控制所產生類別的可見性 |  `PUBLIC` (default) `INTERNAL`  | 
| destinationPackage | 指定所產生類別的套件名稱 |  `RELATIVE` （預設）：結構描述類別會在相對於註釋類別的子套件中產生。依預設，子套件名為 `dynamodbmapper.generatedschemas` ，可透過傳遞字串參數來設定 `ABSOLUTE`：結構描述類別會在相對於應用程式根目錄的絕對套件中產生。根據預設，套件名為 `aws.sdk.kotlin.hll.dynamodbmapper.generatedschemas`，且可透過傳遞字串參數來設定。  | 
| generateGetTableExtension |  控制是否會產生`DynamoDbMapper.get${CLASS_NAME}Table`延伸方法  |  `true` (default) `false`  | 

**Example 程式碼產生外掛程式組態的範例**  
下列範例會設定目的地套件和產生結構描述的可見性：  

```
// build.gradle.kts

import aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.DestinationPackage
import aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.Visibility
import aws.smithy.kotlin.runtime.ExperimentalApi

@OptIn(ExperimentalApi::class)
dynamoDbMapper {
    destinationPackage = DestinationPackage.RELATIVE("my.configured.package")
    visibility = Visibility.INTERNAL
}
```

## 註釋類別
<a name="ddb-mapper-anno-schema-gen-annotate"></a>

結構描述產生器會尋找類別註釋，以決定要產生結構描述的類別。若要選擇加入產生結構描述，請使用 標註您的類別`@[DynamoDbItem](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-item/index.html)`。您也必須將做為項目分割區索引鍵的類別屬性加上註釋`@[DynamoDbPartitionKey](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-partition-key/index.html)`。

下列類別定義顯示產生結構描述所需的最低註釋：

**Example**  

```
@DynamoDbItem
data class Employee(
    @DynamoDbPartitionKey
    val id: Int,
    
    val name: String,
    val role: String,
)
```

### 類別註釋
<a name="ddb-mapper-anno-schema-gen-class-annos"></a>

下列註釋會套用至類別以控制結構描述產生：
+ `@DynamoDbItem`：指定此類別/界面描述資料表中的項目類型。除非明確忽略，否則此類型的所有公有屬性都會對應至屬性。出現時，將會為此類別產生結構描述。
  + `converterName`：選用參數，指出應使用自訂結構描述，而不是結構描述產生器外掛程式所建立的。這是自訂`ItemConverter`類別的完整名稱。[定義自訂項目轉換器](#ddb-mapper-anno-schema-custom) 本節顯示建立和使用自訂結構描述的範例。

### 屬性註釋
<a name="ddb-mapper-anno-schema-gen-prop-annos"></a>

您可以將下列註釋套用至類別屬性，以控制結構描述產生：
+ `@[https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-item/index.html](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-item/index.html)`：指定項目的分割區索引鍵。
+ `@[DynamoDbSortKey](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-sort-key/index.html)`：指定項目的選用排序索引鍵。
+ `@[DynamoDbIgnore](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-ignore/index.html)`：指定此類別屬性不應由 DynamoDB Mapper 轉換為項目屬性或從中轉換。
+ `@[DynamoDbAttribute](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-attribute/index.html)`：指定此類別屬性的選用自訂屬性名稱。

## 定義自訂項目轉換器
<a name="ddb-mapper-anno-schema-custom"></a>

在某些情況下，您可能想要為 類別定義自訂項目轉換器。其中一個原因是，如果您的類別使用結構描述產生器外掛程式不支援的類型。我們使用下列版本的 `Employee`類別做為範例：

```
import kotlin.uuid.Uuid

@DynamoDbItem
data class Employee(
    @DynamoDbPartitionKey
    var id: Int,
    
    var name: String,
    var role: String,
    var workstationId: Uuid
)
```

`Employee` 類別現在使用 類型，結構描述產生器目前不支援此`kotlin.uuid.Uuid`類型。產生結構描述失敗並發生錯誤：`Unsupported attribute type TypeRef(pkg=kotlin.uuid, shortName=Uuid, genericArgs=[], nullable=false)`。此錯誤表示外掛程式無法為此類別產生項目轉換器。因此，我們需要撰寫自己的 。

為此，我們為 類別實作 `[ItemConverter](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.items/-item-converter/index.html)` ，然後透過指定新項目轉換器的完整名稱來修改`@DynamoDbItem`類別註釋。

首先，我們為 `kotlin.uuid.Uuid`類別實作 `[ValueConverter](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.values/-value-converter/index.html)` ：

```
import aws.sdk.kotlin.hll.dynamodbmapper.values.ValueConverter
import aws.sdk.kotlin.services.dynamodb.model.AttributeValue
import kotlin.uuid.Uuid

public val UuidValueConverter = object : ValueConverter<Uuid> {
    override fun convertFrom(to: AttributeValue): Uuid = 
        Uuid.parseHex(to.asS())
        
    override fun convertTo(from: Uuid): AttributeValue = 
        AttributeValue.S(from.toHexString())
}
```

然後，我們為 `Employee`類別實作 `ItemConverter` 。會在 "workstationId" 的屬性描述項中`ItemConverter`使用此新值轉換器：

```
import aws.sdk.kotlin.hll.dynamodbmapper.items.AttributeDescriptor
import aws.sdk.kotlin.hll.dynamodbmapper.items.ItemConverter
import aws.sdk.kotlin.hll.dynamodbmapper.items.SimpleItemConverter
import aws.sdk.kotlin.hll.dynamodbmapper.values.scalars.IntConverter
import aws.sdk.kotlin.hll.dynamodbmapper.values.scalars.StringConverter

public object MyEmployeeConverter : ItemConverter<Employee> by SimpleItemConverter(
    builderFactory = { Employee() },
    build = { this },
    descriptors = arrayOf(
        AttributeDescriptor(
            "id",
            Employee::id,
            Employee::id::set,
            IntConverter,
        ),
        AttributeDescriptor(
            "name",
            Employee::name,
            Employee::name::set,
            StringConverter,
        ),
        AttributeDescriptor(
            "role",
            Employee::role,
            Employee::role::set,
            StringConverter
        ),
        AttributeDescriptor(
            "workstationId",
            Employee::workstationId,
            Employee::workstationId::set,
            UuidValueConverter
        )
    ),
)
```

現在我們已經定義項目轉換器，我們可以將其套用至我們的類別。我們會提供完整類別名稱來更新`@[DynamoDbItem](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper-annotations/aws.sdk.kotlin.hll.dynamodbmapper/-dynamo-db-item/index.html)`註釋以參考項目轉換器，如下所示：

```
import kotlin.uuid.Uuid

@DynamoDbItem("my.custom.item.converter.MyEmployeeConverter")
data class Employee(
    @DynamoDbPartitionKey
    var id: Int,
    
    var name: String,
    var role: String,
    var workstationId: Uuid
)
```

最後，我們可以開始將 類別與 DynamoDB Mapper 搭配使用。

# 手動定義結構描述
<a name="ddb-mapper-code-schemas"></a>

****  
**DynamoDB Mapper 是開發人員預覽版本。其功能不完整，可能會有所變更。**

## 在程式碼中定義結構描述
<a name="ddb-mapper-gs-manual-schema-def"></a>

為了獲得最大的控制和可自訂性，您可以在程式碼中手動定義和自訂結構描述。

如下列程式碼片段所示，相較於使用註釋驅動的結構描述建立，您需要在 `build.gradle.kts` 檔案中包含較少的相依性。

（您可以導覽至 *X.Y.Z* 連結，以查看可用的最新版本。)

```
// build.gradle.kts
val sdkVersion: String = [https://github.com/awslabs/aws-sdk-kotlin/releases/latest](https://github.com/awslabs/aws-sdk-kotlin/releases/latest) 

dependencies {
    implementation("aws.sdk.kotlin:dynamodb-mapper:$sdkVersion-beta") // For the Developer Preview, use the beta version of the latest SDK.
}
```

請注意，您不需要結構描述產生器外掛程式或註釋套件。

Kotlin 類別和 DynamoDB 項目之間的映射需要`[ItemSchema<T>](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.items/-item-schema/index.html)`實作，其中 `T`是 Kotlin 類別的類型。結構描述包含下列元素：
+ 項目轉換器，定義如何在 Kotlin 物件執行個體和 DynamoDB 項目之間轉換。
+ 分割區索引鍵規格，定義分割區索引鍵屬性的名稱和類型。
+ 或者，排序索引鍵規格，定義排序索引鍵屬性的名稱和類型。

在下列程式碼中，我們會手動建立`CarSchema`執行個體：

```
import aws.sdk.kotlin.hll.dynamodbmapper.items.ItemConverter
import aws.sdk.kotlin.hll.dynamodbmapper.items.ItemSchema
import aws.sdk.kotlin.hll.dynamodbmapper.model.itemOf

// We define a schema for this data class.
data class Car(val make: String, val model: String, val initialYear: Int)

// First, define an item converter.
val carConverter = object : ItemConverter<Car> {
    override fun convertTo(from: Car, onlyAttributes: Set<String>?): Item  = itemOf(
        "make" to AttributeValue.S(from.make),
        "model" to AttributeValue.S(from.model),
        "initialYear" to AttributeValue.N(from.initialYear.toString()),
    )

    override fun convertFrom(to: Item): Car = Car(
        make = to["make"]?.asSOrNull() ?: error("Invalid attribute `make`"),
        model = to["model"]?.asSOrNull() ?: error("Invalid attribute `model`"),
        initialYear = to["initialYear"]?.asNOrNull()?.toIntOrNull()
            ?: error("Invalid attribute `initialYear`"),
    )
}

// Next, define the specifications for the partition key and sort key.
val makeKey = KeySpec.String("make")
val modelKey = KeySpec.String("model")

// Finally, create the schema from the converter and key specifications.
// Note that the KeySpec for the partition key comes first in the ItemSchema constructor.
val CarSchema = ItemSchema(carConverter, makeKey, modelKey)
```

先前的程式碼會建立名為 的轉換器`carConverter`，其定義為 的匿名實作`ItemConverter<Car>`。轉換器的 `convertTo`方法接受`Car`引數，並傳回代表 DynamoDB 項目屬性常值索引鍵和值的`Item`執行個體。轉換器的 `convertFrom`方法接受 `Item`引數，並從`Item`引數的屬性值傳回`Car`執行個體。

接下來，程式碼會建立兩個索引鍵規格：一個用於分割區索引鍵，另一個用於排序索引鍵。每個 DynamoDB 資料表或索引都必須只有一個分割區索引鍵，因此每個 DynamoDB Mapper 結構描述定義都必須相應。結構描述也可能有一個排序索引鍵。

在最後一個陳述式中，程式碼會從轉換器和金鑰規格建立 `cars` DynamoDB 資料表的結構描述。

產生的結構描述等同於我們在 [使用類別註釋定義結構描述](ddb-mapper-get-started.md#ddb-mapper-gs-anno-schema-def)區段中產生的註釋驅動結構描述。以下是我們使用的註釋類別，以供參考：

### 具有 DynamoDB Mapper 註釋的汽車類別
<a name="ejd_mxz_ddc"></a>

```
@DynamoDbItem
data class Car(
    @DynamoDbPartitionKey
    val make: String,
    
    @DynamoDbSortKey
    val model: String,
    
    val initialYear: Int
)
```

除了實作您自己的 之外`ItemConverter`，DynamoDB Mapper 還包含數個實用的實作，例如：
+ `[SimpleItemConverter](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.items/-simple-item-converter/index.html)`：使用建置器類別和屬性描述項提供簡單的轉換邏輯。如需[定義自訂項目轉換器](ddb-mapper-anno-schema-gen.md#ddb-mapper-anno-schema-custom)如何使用此實作，請參閱 中的範例。
+ `[HeterogeneousItemConverter](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.items/-heterogeneous-item-converter/index.html)`：透過使用辨別器屬性和委派子類型的`ItemConverter`執行個體，提供多態類型轉換邏輯。
+ `[DocumentConverter](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.items/-document-converter/index.html)`：為 [https://docs.aws.amazon.com/smithy-kotlin/api/latest/runtime-core/aws.smithy.kotlin.runtime.content/-document.html](https://docs.aws.amazon.com/smithy-kotlin/api/latest/runtime-core/aws.smithy.kotlin.runtime.content/-document.html) 物件中的非結構化資料提供轉換邏輯。

# 搭配 DynamoDB Mapper 使用次要索引
<a name="ddb-mapper-secondary-indices"></a>

****  
**DynamoDB Mapper 是開發人員預覽版本。其功能不完整，可能會有所變更。**

## 定義次要索引的結構描述
<a name="ddb-mapper-secondary-indices-schema"></a>

DynamoDB 資料表支援次要索引，該索引可使用與基礎資料表本身上定義的索引鍵不同的索引鍵來存取資料。如同基礎資料表，DynamoDB Mapper 會使用 `[ItemSchema](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.items/-item-schema/index.html)`類型與索引互動。

DynamoDB 次要索引不需要包含基礎資料表中的每個屬性。因此，對應至索引的 Kotlin 類別可能與對應至該索引基礎資料表的 Kotlin 類別不同。在這種情況下，必須為索引類別宣告單獨的結構描述。

下列程式碼會手動建立 DynamoDB `cars`資料表的索引結構描述。

```
import aws.sdk.kotlin.hll.dynamodbmapper.items.ItemConverter
import aws.sdk.kotlin.hll.dynamodbmapper.items.ItemSchema
import aws.sdk.kotlin.hll.dynamodbmapper.model.itemOf

// This is a data class for modelling the index of the Car table. Note
// that it contains a subset of the fields from the Car class and also 
// uses different names for them.
data class Model(val name: String, val manufacturer: String)

// We define an item converter.
val modelConverter = object : ItemConverter<Model> {
    override fun convertTo(from: Model, onlyAttributes: Set<String>?): Item  = itemOf(
        "model" to AttributeValue.S(from.name),
        "make" to AttributeValue.S(from.manufacturer),
    )

    override fun convertFrom(to: Item): Model = Model(
        name = to["model"]?.asSOrNull() ?: error("Invalid attribute `model`"),
        manufacturer = to["make"]?.asSOrNull() ?: error("Invalid attribute `make`"),
    )
}
val modelKey = KeySpec.String("model")
val makeKey = KeySpec.String("make")

val modelSchema = ItemSchema(modelConverter, modelKey, makeKey) // The partition key specification is the second parameter.

/* Note that `Model` index's partition key is `model` and its sort key is `make`,
   whereas the `Car` base table uses `make` as the partition key and `model` as the sort key:

        @DynamoDbItem
        data class Car(
            @DynamoDbPartitionKey
            val make: String,
    
            @DynamoDbSortKey
            val model: String,
    
            val initialYear: Int
        )
*/
```

我們現在可以在 操作中使用`Model`執行個體。

## 在 操作中使用次要索引
<a name="ddb-mapper-gs-index-ops"></a>

DynamoDB Mapper 支援索引上的操作子集，即 `queryPaginated`和 `scanPaginated`。若要在索引上調用這些操作，您必須先從資料表物件取得索引的參考。在下列範例中，我們使用先前為`cars-by-model`索引`modelSchema`建立的 （此處未顯示建立）：

```
val table = mapper.getTable("cars", CarSchema)
val index = table.getIndex("cars-by-model", modelSchema)

val modelFlow = index
    .scanPaginated { }
    .items()

modelFlow.collect { model -> println(model) }
```

# 使用表達式
<a name="ddb-mapper-expressions"></a>

****  
**DynamoDB Mapper 是開發人員預覽版本。其功能不完整，可能會有所變更。**

某些 DynamoDB 操作接受您可以用來指定限制條件或條件[的表達](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html)式。DynamoDB Mapper 提供慣用的 Kotlin DSL 來建立表達式。DSL 為您的程式碼提供更大的結構和可讀性，也可讓您更輕鬆地撰寫表達式。

本節說明 DSL 語法並提供各種範例。

## 在 操作中使用表達式
<a name="ddb-mapper-expressions-basic-usage"></a>

您可以在 等操作中使用表達式`scan`，它們會根據您定義的條件篩選傳回的項目。若要搭配 DynamoDB Mapper 使用表達式，請在操作請求中新增表達式元件。

下列程式碼片段顯示 `scan`操作中使用的篩選條件表達式範例。它使用 lambda 引數來描述篩選條件，限制項目傳回至`year`屬性值為 2001 的項目：

```
val table = // A table instance.

table.scanPaginated {
    filter {
        attr("year") eq 2001
    }
}
```

下列範例顯示支援兩個位置表達式`query`的操作：排序索引鍵篩選和非索引鍵篩選：

```
table.queryPaginated {
    keyCondition = KeyFilter(partitionKey = 1000) { sortKey startsWith "M" }
    filter {
        attr("year") eq 2001
    }
}
```

先前的程式碼會篩選符合所有三個條件的結果：
+ 分割區索引鍵屬性值為 1000 *-AND-*
+ 排序索引鍵屬性值以字母 *M* *-AND-* 開頭
+ year 屬性值為 2001

## DSL 元件
<a name="ddb-mapper-expressions-dsl"></a>

DSL 語法會公開您用來建置表達式的多種元件類型，如下所述。

### 屬性
<a name="ddb-mapper-expressions-dsl-attrs"></a>

大多數條件參考屬性，由其金鑰或文件路徑識別。使用 DSK，您可以使用 `attr`函數建立所有屬性參考，並選擇性地進行其他修改。

下列程式碼顯示從簡單到複雜的範例屬性參考範圍，例如索引的清單取消參考和索引鍵的映射取消參考：

```
attr("foo")           // Refers to the value of top-level attribute `foo`.

attr("foo")[3]        // Refers to the value at index 3 in the list value of
                      // attribute `foo`.

attr("foo")[3]["bar"] // Refers to the value of key `bar` in the map value at
                      // index 3 of the list value of attribute `foo`.
```

### 等式和不等式
<a name="ddb-mapper-expressions-dsl-eq-and-ineq"></a>

您可以依等式和不等式比較表達式中的屬性值。您可以將屬性值與常值或其他屬性值進行比較。您用來指定條件的函數包括：
+ `eq`： 等於 （相當於 `==`)
+ `neq`： 不等於 （相當於 `!=`)
+ `gt`： 大於 （相當於 `>`)
+ `gte`：大於或等於 （相當於 `>=`)
+ `lt`： 小於 （相當於 `<`)
+ `lte`：小於或等於 （相當於 `<=`)

您可以使用 infix 標記法將比較函數與引數結合，如下列範例所示：

```
attr("foo") eq 42           // Uses a literal. Specifies that the attribute value `foo` must be
                            // equal to 42.

attr("bar") gte attr("baz") // Uses another attribute value. Specifies that the attribute 
                            // value `bar` must be greater than or equal to the
                            // attribute value of `baz`.
```

### 範圍和集
<a name="ddb-mapper-expressions-dsl-ranges-sets"></a>

除了單一值之外，您還可以將屬性值與範圍或集合中的多個值進行比較。您可以使用 infix `[isIn](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.expressions/-filter/is-in.html)`函數進行比較，如下列範例所示：

```
attr("foo") isIn 0..99  // Specifies that the attribute value `foo` must be
                        // in the range of `0` to `99` (inclusive).

attr("foo") isIn setOf( // Specifies that the attribute value `foo` must be
    "apple",            // one of `apple`, `banana`, or `cherry`.
    "banana",
    "cherry",
)
```

`isIn` 函數為集合 （例如 `Set<String>`) 和您可以表達為 Kotlin 的邊界 `[ClosedRange<T>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.ranges/-closed-range/)`（例如 `[IntRange](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.ranges/-int-range/)`) 提供過載。對於您無法表達為 的邊界 `ClosedRange<T>`（例如位元組陣列或其他屬性參考），您可以使用 `[isBetween](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.expressions/-filter/is-between.html)`函數：

```
val lowerBytes = byteArrayOf(0x48, 0x65, 0x6c)  // Specifies that the attribute value
val upperBytes = byteArrayOf(0x6c, 0x6f, 0x21)  // `foo` is between the values
attr("foo").isBetween(lowerBytes, upperBytes)   // `0x48656c` and `0x6c6f21`

attr("foo").isBetween(attr("bar"), attr("baz")) // Specifies that the attribute value
                                                // `foo` is between the values of
                                                // attributes `bar` and `baz`.
```

### 布林值邏輯
<a name="ddb-mapper-expressions-dsl-boolean"></a>

您可以使用下列函數結合個別條件或使用布林邏輯進行修改：
+ `and`：每個條件都必須是 true （等於` &&`)
+ `or`：至少一個條件必須為 true （相當於 `||`)
+ `not`：指定的條件必須是 false （相當於 `!`)

下列範例顯示每個 函數：

```
and(                           // Both conditions must be met:
    attr("foo") eq "banana",   // * attribute value `foo` must equal `banana`
    attr("bar") isIn 0..99,    // * attribute value `bar` must be between
)                              //   0 and 99 (inclusive)

or(                            // At least one condition must be met:
    attr("foo") eq "cherry",   // * attribute value `foo` must equal `cherry`
    attr("bar") isIn 100..199, // * attribute value `bar` must be between
)                              //   100 and 199 (inclusive)

not(                           // The attribute value `foo` must *not* be
    attr("baz") isIn setOf(    // one of `apple`, `banana`, or `cherry`.
        "apple",               // Stated another way, the attribute value
        "banana",              // must be *anything except* `apple`, `banana`,
        "cherry",              // or `cherry`--including potentially a
    ),                         // non-string value or no value at all.
)
```

您可以依布林函數進一步合併布林值條件，以建立巢狀邏輯，如下列表達式所示：

```
or(
    and(
        attr("foo") eq 123,
        attr("bar") eq "abc",
    ),
    and(
        attr("foo") eq 234,
        attr("bar") eq "bcd",
    ),
)
```

先前的表達式會篩選符合下列任一條件的結果：
+  這兩個條件都是 true：
  + `foo` 屬性值為 123 *-AND-*
  + `bar` 屬性值為 "abc"
+ 這兩個條件都是 true：
  + `foo` 屬性值為 234 *-AND-*
  + `bar` 屬性值為 "bcd"

這相當於下列 Kotlin 布林表達式：

```
(foo == 123 && bar == "abc") || (foo == 234 && bar == "bcd")
```

### 函數和屬性
<a name="ddb-mapper-expressions-dsl-functions"></a>

下列函數和屬性提供額外的表達式功能：
+ `[contains](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.expressions/-filter/contains.html)`：檢查字串/清單屬性值是否包含指定的值
+ `[exists](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.expressions/-filter/exists.html)`：檢查是否已定義屬性並保留任何值 （包括 `null`)
+ `[notExists](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.expressions/-filter/not-exists.html)`：檢查屬性是否未定義
+ `[isOfType](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.expressions/-filter/is-of-type.html)`：檢查屬性值是否為指定類型，例如字串、數字、布林值等
+ `[size](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.expressions/-filter/size.html)`：取得屬性的大小，例如集合中的元素數量或字串的長度
+ `[startsWith](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb-mapper/aws.sdk.kotlin.hll.dynamodbmapper.expressions/-filter/starts-with.html)`：檢查字串屬性值是否以指定的子字串開頭

下列範例顯示您可以在表達式中使用的其他函數和屬性的使用：

```
attr("foo") contains "apple" // Specifies that the attribute value `foo` must be
                             // a list that contains an `apple` element or a string
                             // which contains the substring `apple`.

attr("bar").exists()         // Specifies that the `bar` must exist and have a
                             // value (including potentially `null`).

attr("baz").size lt 100      // Specifies that the attribute value `baz` must have
                             // a size of less than 100.

attr("qux") isOfType AttributeType.String // Specifies that the attribute `qux`
                                          // must have a string value.
```

### 排序金鑰篩選條件
<a name="ddb-mapper-expressions-dsl-sort-key"></a>

排序索引鍵 （例如在`query`操作的 `keyCondition` 參數中） 上的篩選條件表達式不會使用具名屬性值。若要在篩選條件中使用排序索引鍵，您必須在所有比較`sortKey`中使用 關鍵字。`sortKey` 關鍵字會取代 `attr("<sort key name>")`，如下列範例所示：

```
sortKey startsWith "abc" // The sort key attribute value must begin with the
                         // substring `abc`.

sortKey isIn 0..99       // The sort key attribute value must be between 0
                         // and 99 (inclusive).
```

您不能將排序索引鍵篩選條件與布林邏輯結合，它們僅支援上述比較的子集：
+ [相等性和不相等性](#ddb-mapper-expressions-dsl-eq-and-ineq)：支援的所有比較
+ [範圍和集](#ddb-mapper-expressions-dsl-ranges-sets)：支援的所有比較
+ [布林值邏輯](#ddb-mapper-expressions-dsl-boolean)：不支援
+ [函數和屬性](#ddb-mapper-expressions-dsl-functions)：僅`startsWith`支援