

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

# 使用不可变数据类
<a name="ddb-en-client-use-immut"></a>

DynamoDB 增强型客户端 API 的映射功能适用于不可变的数据类。不可变类只有 getter，且需要一个生成器类，使 SDK 可用来创建该类的实例。不可变类不像 [Customer 类](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust)那样使用 `@DynamoDbBean` 注释，而是使用 `@DynamoDbImmutable` 注释，该注释采用一个指示要使用的生成器类的参数。

以下类是 `Customer` 的不可变版本。

```
package org.example.tests.model.immutable;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbImmutable;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.time.Instant;

@DynamoDbImmutable(builder = CustomerImmutable.Builder.class)
public class CustomerImmutable {
    private final String id;
    private final String name;
    private final String email;
    private final Instant regDate;

    private CustomerImmutable(Builder b) {
        this.id = b.id;
        this.email = b.email;
        this.name = b.name;
        this.regDate = b.regDate;
    }

    // This method will be automatically discovered and used by the TableSchema.
    public static Builder builder() { return new Builder(); }

    @DynamoDbPartitionKey
    public String id() { return this.id; }

    @DynamoDbSortKey
    public String email() { return this.email; }

    @DynamoDbSecondaryPartitionKey(indexNames = "customers_by_name")
    public String name() { return this.name; }

    @DynamoDbSecondarySortKey(indexNames = {"customers_by_date", "customers_by_name"})
    public Instant regDate() { return this.regDate; }

    public static final class Builder {
        private String id;
        private String email;
        private String name;
        private Instant regDate;

        // The private Builder constructor is visible to the enclosing CustomerImmutable class.
        private Builder() {}

        public Builder id(String id) { this.id = id; return this; }
        public Builder email(String email) { this.email = email; return this; }
        public Builder name(String name) { this.name = name; return this; }
        public Builder regDate(Instant regDate) { this.regDate = regDate; return this; }

        // This method will be automatically discovered and used by the TableSchema.
        public CustomerImmutable build() { return new CustomerImmutable(this); }
    }
}
```

使用 `@DynamoDbImmutable` 注释数据类时，您必须满足以下要求。

1. 每个既不覆盖 `Object.class` 又未使用 `@DynamoDbIgnore` 注释的方法都必须是 DynamoDB 表属性的 getter。

1. 每个 getter 在生成器类上都必须有一个对应的区分大小写的 setter。

1. 必须仅满足以下任一构造条件。
   + 生成器类必须具有公共默认构造函数。
   + 数据类必须有一个名为 `builder()` 的公共静态方法，该方法不带任何参数并返回生成器类的实例。此选项显示在不可变 `Customer` 类中。

1.  生成器类必须有一个名为 `build()` 的公共方法，该方法不带任何参数并返回不可变类的实例。

要为不可变类创建 `TableSchema`，请使用 `TableSchema` 上的 `fromImmutableClass()` 方法，如以下代码段所示。

```
static final TableSchema<CustomerImmutable> customerImmutableTableSchema = 
                         TableSchema.fromImmutableClass(CustomerImmutable.class);
```

就像您可以从可变类创建 DynamoDB 表一样，您也可以通过*一次性* 调用 `DynamoDbTable` 的 `createTable()` 从不可变类创建该表，如以下代码段示例所示。

```
static void createTableFromImmutable(DynamoDbEnhancedClient enhancedClient, String tableName, DynamoDbWaiter waiter){
    // First, create an in-memory representation of the table using the 'table()' method of the DynamoDb Enhanced Client.
    // 'table()' accepts a name for the table and a TableSchema instance that you created previously.
    DynamoDbTable<CustomerImmutable> customerDynamoDbTable = enhancedClient
            .table(tableName, TableSchema.fromImmutableClass(CustomerImmutable.class));
        
    // Second, call the 'createTable()' method on the DynamoDbTable instance.
    customerDynamoDbTable.createTable();
    waiter.waitUntilTableExists(b -> b.tableName(tableName));
}
```

## 使用第三方库，例如 Lombok
<a name="ddb-en-client-use-immut-lombok"></a>

第三方库（例如 [Project Lombok](https://projectlombok.org/)）可帮助生成与不可变对象关联的样板代码。只要数据类遵循本部分详述的约定，DynamoDB 增强型客户端 API 就可以与这些库结合使用。

以下示例演示带有 Lombok 注释的不可变 `CustomerImmutable` 类。请注意 Lombok 的 `onMethod` 功能是如何将基于属性的 DynamoDB 注释（例如 `@DynamoDbPartitionKey`）复制到生成的代码中的。

```
@Value
@Builder
@DynamoDbImmutable(builder = Customer.CustomerBuilder.class)
public class Customer {
    @Getter(onMethod_=@DynamoDbPartitionKey)
    private String id;

    @Getter(onMethod_=@DynamoDbSortKey)
    private String email;

    @Getter(onMethod_=@DynamoDbSecondaryPartitionKey(indexNames = "customers_by_name"))
    private String name;

    @Getter(onMethod_=@DynamoDbSecondarySortKey(indexNames = {"customers_by_date", "customers_by_name"}))
    private Instant createdDate;
}
```