

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Bekerja dengan DynamoDB
<a name="examples-dynamodb"></a>

[DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) adalah layanan database NoSQL yang dikelola sepenuhnya yang memberikan kinerja yang cepat dan dapat diprediksi dengan skalabilitas yang mulus. Bagian ini menunjukkan cara bekerja dengan DynamoDB menggunakan 2.x. AWS SDK untuk Java 

## Pilih klien DynamoDB Anda
<a name="ddb-clients-overview"></a>

SDK menyediakan dua pendekatan utama untuk bekerja dengan DynamoDB:

Klien tingkat rendah () `DynamoDbClient`  
Menyediakan akses langsung ke operasi DynamoDB dengan kontrol penuh atas permintaan dan tanggapan. Gunakan klien ini ketika Anda membutuhkan kontrol halus atau bekerja dengan skema dinamis.

Klien yang disempurnakan (`DynamoDbEnhancedClient`)  
Menawarkan pemrograman berorientasi objek dengan pemetaan otomatis antara objek Java dan item DynamoDB. Juga menyediakan kemampuan berorientasi dokumen untuk bekerja dengan data seperti JSON yang tidak mengikuti skema tetap. Gunakan klien ini saat bekerja dengan model data yang terdefinisi dengan baik atau data tipe dokumen.

## Konfigurasikan klien DynamoDB
<a name="ddb-configuration-setup"></a>

Sebelum bekerja dengan DynamoDB, konfigurasikan klien Anda untuk kinerja dan keandalan yang optimal.

### Memahami perilaku coba lagi DynamoDB
<a name="ddb-retry-behavior"></a>

Klien DynamoDB menggunakan hitungan coba ulang maksimum default 8, yang lebih tinggi dari klien lain. Layanan AWS Jumlah percobaan ulang yang lebih tinggi ini membantu menangani sifat terdistribusi DynamoDB dan batasan kapasitas sementara. Untuk informasi lebih lanjut tentang strategi coba lagi, lihat[Konfigurasikan perilaku coba lagi di AWS SDK for Java 2.x](retry-strategy.md).

### Optimalkan kinerja dengan titik akhir berbasis akun
<a name="ddb-account-based-endpoints-v2"></a>

DynamoDB [AWS menawarkan endpoint berbasis akun](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.SDKOverview.html#Programming.SDKs.endpoints) yang meningkatkan kinerja dengan menggunakan ID akun AWS Anda untuk merampingkan perutean permintaan. 

Untuk menggunakan fitur ini, Anda memerlukan versi 2.28.4 atau yang lebih besar dari. AWS SDK for Java 2.x Anda dapat menemukan versi terbaru di repositori [pusat Maven](https://central.sonatype.com/artifact/software.amazon.awssdk/bom/versions). Versi SDK yang didukung secara otomatis menggunakan titik akhir baru.

Untuk memilih keluar dari perutean berbasis akun, pilih salah satu opsi berikut:
+ Konfigurasikan klien `AccountIdEndpointMode` layanan DynamoDB dengan set ke. `DISABLED`
+ Tetapkan variabel lingkungan.
+ Mengatur properti sistem JVM.
+ Perbarui setelan file AWS konfigurasi bersama.

Contoh berikut menunjukkan cara menonaktifkan routing berbasis akun dengan mengkonfigurasi klien layanan DynamoDB:

```
DynamoDbClient.builder()
                 .accountIdEndpointMode(AccountIdEndpointMode.DISABLED)
                 .build();
```

Untuk informasi selengkapnya tentang opsi konfigurasi lainnya, lihat [Titik akhir berbasis akun](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html) di Panduan Referensi Alat AWS SDKs dan Alat.

## Apa yang dibahas dalam topik ini
<a name="ddb-topics-overview"></a>

Bagian berikut menunjukkan cara bekerja dengan DynamoDB:
+ [Bekerja dengan tabel di DynamoDB](examples-dynamodb-tables.md)- Buat, jelaskan, perbarui, dan hapus tabel
+ [Bekerja dengan item di DynamoDB](examples-dynamodb-items.md)- Tambahkan, ambil, dan perbarui item individual
+ [Peta objek Java ke item DynamoDB dengan AWS SDK for Java 2.x](dynamodb-enhanced-client.md)- Gunakan pemetaan objek dan data berorientasi dokumen dengan Klien yang Ditingkatkan

Untuk contoh kode DynamoDB tambahan, lihat contoh kode [DynamoDB di Pustaka Contoh](java_dynamodb_code_examples.md) Kode. AWS 

# Bekerja dengan tabel di DynamoDB
<a name="examples-dynamodb-tables"></a>

Tabel adalah wadah untuk semua item dalam DynamoDB database. Sebelum Anda dapat menambah atau menghapus data dari DynamoDB, Anda harus membuat tabel.

Untuk setiap tabel, Anda harus mendefinisikan:
+ *Nama* tabel yang unik untuk akun dan Wilayah Anda.
+ *Kunci utama* yang setiap nilainya harus unik; tidak ada dua item dalam tabel Anda yang dapat memiliki nilai kunci primer yang sama.

  Kunci primer bisa *sederhana*, terdiri dari kunci partisi tunggal (HASH), atau *komposit*, yang terdiri dari partisi dan kunci sort (RANGE).

  Setiap nilai kunci memiliki *tipe data* terkait, disebutkan oleh kelas. [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ScalarAttributeType.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ScalarAttributeType.html) Nilai kunci dapat berupa biner (B), numerik (N), atau string (S). Untuk informasi selengkapnya, lihat [Aturan Penamaan dan Jenis Data](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) di Panduan Amazon DynamoDB Pengembang.
+  *Throughput yang disediakan* adalah nilai yang menentukan jumlah unit kapasitas baca/tulis yang dicadangkan untuk tabel.
**catatan**  
 [Amazon DynamoDB Penetapan harga](https://aws.amazon.com/dynamodb/pricing/) didasarkan pada nilai throughput yang disediakan yang Anda tetapkan pada tabel Anda, jadi cadangkan hanya kapasitas sebanyak yang Anda pikir Anda perlukan untuk tabel Anda.

  Throughput yang disediakan untuk tabel dapat dimodifikasi kapan saja, sehingga Anda dapat menyesuaikan kapasitas saat kebutuhan Anda berubah.

## Membuat tabel
<a name="dynamodb-create-table"></a>

Gunakan `DynamoDbClient’s` `createTable` metode ini untuk membuat DynamoDB tabel baru. Anda perlu membangun atribut tabel dan skema tabel, yang keduanya digunakan untuk mengidentifikasi kunci utama tabel Anda. Anda juga harus menyediakan nilai throughput awal yang disediakan dan nama tabel.

**catatan**  
Jika tabel dengan nama yang Anda pilih sudah ada, a `[DynamoDbException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/DynamoDbException.html)` dilemparkan.

### Buat tabel dengan kunci primer sederhana
<a name="dynamodb-create-table-simple"></a>

Kode ini membuat tabel dengan satu atribut yang merupakan kunci utama sederhana tabel. contoh menggunakan `[AttributeDefinition](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeDefinition.html)` dan `[KeySchemaElement](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/KeySchemaElement.html)` objek untuk. [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CreateTableRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CreateTableRequest.html)

 **Impor** 

```
import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.CreateTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.waiters.DynamoDbWaiter;
```

 **Kode** 

```
    public static String createTable(DynamoDbClient ddb, String tableName, String key) {

        DynamoDbWaiter dbWaiter = ddb.waiter();
        CreateTableRequest request = CreateTableRequest.builder()
                .attributeDefinitions(AttributeDefinition.builder()
                        .attributeName(key)
                        .attributeType(ScalarAttributeType.S)
                        .build())
                .keySchema(KeySchemaElement.builder()
                        .attributeName(key)
                        .keyType(KeyType.HASH)
                        .build())
                .provisionedThroughput(ProvisionedThroughput.builder()
                        .readCapacityUnits(new Long(10))
                        .writeCapacityUnits(new Long(10))
                        .build())
                .tableName(tableName)
                .build();

        String newTable ="";
        try {
            CreateTableResponse response = ddb.createTable(request);
            DescribeTableRequest tableRequest = DescribeTableRequest.builder()
                    .tableName(tableName)
                    .build();

            // Wait until the Amazon DynamoDB table is created
            WaiterResponse<DescribeTableResponse> waiterResponse =  dbWaiter.waitUntilTableExists(tableRequest);
            waiterResponse.matched().response().ifPresent(System.out::println);

            newTable = response.tableDescription().tableName();
            return newTable;

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
       return "";
    }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTable.java) di GitHub.

### Buat tabel dengan kunci primer komposit
<a name="dynamodb-create-table-composite"></a>

Contoh berikut membuat tabel dengan dua atribut. Kedua atribut digunakan untuk kunci primer komposit.

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.CreateTableResponse;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
```

 **Kode** 

```
    public static String createTableComKey(DynamoDbClient ddb, String tableName) {
        CreateTableRequest request = CreateTableRequest.builder()
                .attributeDefinitions(
                        AttributeDefinition.builder()
                                .attributeName("Language")
                                .attributeType(ScalarAttributeType.S)
                                .build(),
                        AttributeDefinition.builder()
                                .attributeName("Greeting")
                                .attributeType(ScalarAttributeType.S)
                                .build())
                .keySchema(
                        KeySchemaElement.builder()
                                .attributeName("Language")
                                .keyType(KeyType.HASH)
                                .build(),
                        KeySchemaElement.builder()
                                .attributeName("Greeting")
                                .keyType(KeyType.RANGE)
                                .build())
                .provisionedThroughput(
                        ProvisionedThroughput.builder()
                                .readCapacityUnits(new Long(10))
                                .writeCapacityUnits(new Long(10)).build())
                .tableName(tableName)
                .build();

       String tableId = "";

       try {
            CreateTableResponse result = ddb.createTable(request);
            tableId = result.tableDescription().tableId();
            return tableId;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
       return "";
    }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTableCompositeKey.java) di GitHub.

## Mencantumkan tabel
<a name="dynamodb-list-tables"></a>

Anda dapat membuat daftar tabel di Wilayah tertentu dengan memanggil `DynamoDbClient’s` `listTables` metode.

**catatan**  
Jika tabel bernama tidak ada untuk akun dan Wilayah Anda, a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)dilemparkan.

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse;
import software.amazon.awssdk.services.dynamodb.model.ListTablesRequest;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import java.util.List;
```

 **Kode** 

```
    public static void listAllTables(DynamoDbClient ddb){

        boolean moreTables = true;
        String lastName = null;

        while(moreTables) {
            try {
                ListTablesResponse response = null;
                if (lastName == null) {
                    ListTablesRequest request = ListTablesRequest.builder().build();
                    response = ddb.listTables(request);
                } else {
                    ListTablesRequest request = ListTablesRequest.builder()
                            .exclusiveStartTableName(lastName).build();
                    response = ddb.listTables(request);
                }

                List<String> tableNames = response.tableNames();

                if (tableNames.size() > 0) {
                    for (String curName : tableNames) {
                        System.out.format("* %s\n", curName);
                    }
                } else {
                    System.out.println("No tables found!");
                    System.exit(0);
                }

                lastName = response.lastEvaluatedTableName();
                if (lastName == null) {
                    moreTables = false;
                }
            } catch (DynamoDbException e) {
                System.err.println(e.getMessage());
                System.exit(1);
            }
        }
        System.out.println("\nDone!");
    }
```

Secara default, hingga 100 tabel dikembalikan per panggilan—gunakan `lastEvaluatedTableName` pada [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ListTablesResponse.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ListTablesResponse.html)objek yang dikembalikan untuk mendapatkan tabel terakhir yang dievaluasi. Anda dapat menggunakan nilai ini untuk memulai daftar setelah nilai terakhir yang dikembalikan dari daftar sebelumnya.

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/ListTables.java) di GitHub.

## Jelaskan (dapatkan informasi tentang) tabel
<a name="dynamodb-describe-table"></a>

Gunakan `DynamoDbClient’s` `describeTable` metode ini untuk mendapatkan informasi tentang tabel.

**catatan**  
Jika tabel bernama tidak ada untuk akun dan Wilayah Anda, a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)dilemparkan.

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughputDescription;
import software.amazon.awssdk.services.dynamodb.model.TableDescription;
import java.util.List;
```

 **Kode** 

```
    public static void describeDymamoDBTable(DynamoDbClient ddb,String tableName ) {

        DescribeTableRequest request = DescribeTableRequest.builder()
                .tableName(tableName)
                .build();

        try {
            TableDescription tableInfo =
                    ddb.describeTable(request).table();

            if (tableInfo != null) {
                System.out.format("Table name  : %s\n",
                        tableInfo.tableName());
                System.out.format("Table ARN   : %s\n",
                        tableInfo.tableArn());
                System.out.format("Status      : %s\n",
                        tableInfo.tableStatus());
                System.out.format("Item count  : %d\n",
                        tableInfo.itemCount().longValue());
                System.out.format("Size (bytes): %d\n",
                        tableInfo.tableSizeBytes().longValue());

                ProvisionedThroughputDescription throughputInfo =
                        tableInfo.provisionedThroughput();
                System.out.println("Throughput");
                System.out.format("  Read Capacity : %d\n",
                        throughputInfo.readCapacityUnits().longValue());
                System.out.format("  Write Capacity: %d\n",
                        throughputInfo.writeCapacityUnits().longValue());

                List<AttributeDefinition> attributes =
                        tableInfo.attributeDefinitions();
                System.out.println("Attributes");

                for (AttributeDefinition a : attributes) {
                    System.out.format("  %s (%s)\n",
                            a.attributeName(), a.attributeType());
                }
            }
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        System.out.println("\nDone!");
    }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DescribeTable.java) di GitHub.

## Ubah (perbarui) tabel
<a name="dynamodb-update-table"></a>

Anda dapat memodifikasi nilai throughput yang disediakan tabel kapan saja dengan memanggil metode. `DynamoDbClient’s` `updateTable`

**catatan**  
Jika tabel bernama tidak ada untuk akun dan Wilayah Anda, a [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)dilemparkan.

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.UpdateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
```

 **Kode** 

```
    public static void updateDynamoDBTable(DynamoDbClient ddb,
                                           String tableName,
                                           Long readCapacity,
                                           Long writeCapacity) {

        System.out.format(
                "Updating %s with new provisioned throughput values\n",
                tableName);
        System.out.format("Read capacity : %d\n", readCapacity);
        System.out.format("Write capacity : %d\n", writeCapacity);

        ProvisionedThroughput tableThroughput = ProvisionedThroughput.builder()
                .readCapacityUnits(readCapacity)
                .writeCapacityUnits(writeCapacity)
                .build();

        UpdateTableRequest request = UpdateTableRequest.builder()
                .provisionedThroughput(tableThroughput)
                .tableName(tableName)
                .build();

        try {
            ddb.updateTable(request);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }

        System.out.println("Done!");
    }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateTable.java) di GitHub.

## Menghapus tabel
<a name="dynamodb-delete-table"></a>

Untuk menghapus tabel, panggil `DynamoDbClient’s` `deleteTable` metode dan berikan nama tabel.

**catatan**  
Jika tabel bernama tidak ada untuk akun dan Wilayah Anda, a [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)dilemparkan.

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
```

 **Kode** 

```
    public static void deleteDynamoDBTable(DynamoDbClient ddb, String tableName) {

        DeleteTableRequest request = DeleteTableRequest.builder()
                .tableName(tableName)
                .build();

        try {
            ddb.deleteTable(request);

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        System.out.println(tableName +" was successfully deleted!");
    }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteTable.java) di GitHub.

## Informasi lain
<a name="more-information"></a>
+  [Pedoman untuk Bekerja dengan Tabel](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html) di Panduan Amazon DynamoDB Pengembang
+  [Bekerja dengan Tabel DynamoDB di](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html) Panduan Amazon DynamoDB Pengembang

# Bekerja dengan item di DynamoDB
<a name="examples-dynamodb-items"></a>

Dalam DynamoDB, item adalah kumpulan *atribut*, yang masing-masing memiliki *nama* dan *nilai*. Nilai atribut dapat berupa skalar, set, atau jenis dokumen. Untuk informasi selengkapnya, lihat [Aturan Penamaan dan Jenis Data](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) di Panduan Amazon DynamoDB Pengembang.

## Ambil (dapatkan) item dari tabel
<a name="dynamodb-get-item"></a>

Panggil `getItem` metode ini dan berikan [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html)objek dengan nama tabel dan nilai kunci primer dari item yang Anda inginkan. DynamoDbClient Ia mengembalikan [GetItemResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemResponse.html)objek dengan semua atribut untuk item itu. Anda dapat menentukan satu atau lebih [ekspresi proyeksi](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html) dalam `GetItemRequest` untuk mengambil atribut tertentu.

Anda dapat menggunakan `item()` metode `GetItemResponse` objek yang dikembalikan untuk mengambil [Map](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) of key (String) dan value ([AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html)) pasangan yang terkait dengan item tersebut.

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
```

 **Kode** 

```
    public static void getDynamoDBItem(DynamoDbClient ddb,String tableName,String key,String keyVal ) {

        HashMap<String,AttributeValue> keyToGet = new HashMap<String,AttributeValue>();

        keyToGet.put(key, AttributeValue.builder()
                .s(keyVal).build());

        GetItemRequest request = GetItemRequest.builder()
                .key(keyToGet)
                .tableName(tableName)
                .build();

        try {
            Map<String,AttributeValue> returnedItem = ddb.getItem(request).item();

            if (returnedItem != null) {
                Set<String> keys = returnedItem.keySet();
                System.out.println("Amazon DynamoDB table attributes: \n");

                for (String key1 : keys) {
                    System.out.format("%s: %s\n", key1, returnedItem.get(key1).toString());
                }
            } else {
                System.out.format("No item found with the key %s!\n", key);
            }
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/GetItem.java) di GitHub.

## Ambil (dapatkan) item dari tabel menggunakan klien asinkron
<a name="id1ddb"></a>

Memanggil `getItem` metode DynamoDbAsyncClient dan meneruskannya [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html)objek dengan nama tabel dan nilai kunci utama dari item yang Anda inginkan.

Anda dapat mengembalikan instance [Collection](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Collection.html) dengan semua atribut untuk item tersebut (lihat contoh berikut).

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
```

 **Kode** 

```
    public static void getItem(DynamoDbAsyncClient client, String tableName, String key,  String keyVal) {

        HashMap<String, AttributeValue> keyToGet =
                new HashMap<String, AttributeValue>();

        keyToGet.put(key, AttributeValue.builder()
                .s(keyVal).build());

        try {

            // Create a GetItemRequest instance
            GetItemRequest request = GetItemRequest.builder()
                    .key(keyToGet)
                    .tableName(tableName)
                    .build();

            // Invoke the DynamoDbAsyncClient object's getItem
            java.util.Collection<AttributeValue> returnedItem = client.getItem(request).join().item().values();

            // Convert Set to Map
            Map<String, AttributeValue> map = returnedItem.stream().collect(Collectors.toMap(AttributeValue::s, s->s));
            Set<String> keys = map.keySet();
            for (String sinKey : keys) {
                System.out.format("%s: %s\n", sinKey, map.get(sinKey).toString());
            }

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/DynamoDBAsyncGetItem.java) di GitHub.

## Tambahkan item baru ke tabel
<a name="dynamodb-add-item"></a>

Buat [Peta](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) pasangan kunci-nilai yang mewakili atribut item. Ini harus menyertakan nilai untuk bidang kunci utama tabel. Jika item yang diidentifikasi oleh kunci utama sudah ada, bidangnya *diperbarui* oleh permintaan.

**catatan**  
Jika tabel bernama tidak ada untuk akun dan wilayah Anda, a [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)dilemparkan.

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import java.util.HashMap;
```

 **Kode** 

```
    public static void putItemInTable(DynamoDbClient ddb,
                                      String tableName,
                                      String key,
                                      String keyVal,
                                      String albumTitle,
                                      String albumTitleValue,
                                      String awards,
                                      String awardVal,
                                      String songTitle,
                                      String songTitleVal){

        HashMap<String,AttributeValue> itemValues = new HashMap<String,AttributeValue>();

        // Add all content to the table
        itemValues.put(key, AttributeValue.builder().s(keyVal).build());
        itemValues.put(songTitle, AttributeValue.builder().s(songTitleVal).build());
        itemValues.put(albumTitle, AttributeValue.builder().s(albumTitleValue).build());
        itemValues.put(awards, AttributeValue.builder().s(awardVal).build());

        PutItemRequest request = PutItemRequest.builder()
                .tableName(tableName)
                .item(itemValues)
                .build();

        try {
            ddb.putItem(request);
            System.out.println(tableName +" was successfully updated");

        } catch (ResourceNotFoundException e) {
            System.err.format("Error: The Amazon DynamoDB table \"%s\" can't be found.\n", tableName);
            System.err.println("Be sure that it exists and that you've typed its name correctly!");
            System.exit(1);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/PutItem.java) di GitHub.

## Memperbarui item yang ada dalam tabel
<a name="dynamodb-update-item"></a>

Anda dapat memperbarui atribut untuk item yang sudah ada dalam tabel dengan menggunakan `updateItem` metode, memberikan nama tabel, nilai kunci primer, dan peta bidang yang akan diperbarui. DynamoDbClient

**catatan**  
Jika tabel bernama tidak ada untuk akun dan wilayah Anda, atau jika item yang diidentifikasi oleh kunci utama yang Anda lewati tidak ada, a akan [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)ditampilkan.

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.AttributeAction;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.AttributeValueUpdate;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import java.util.HashMap;
```

 **Kode** 

```
    public static void updateTableItem(DynamoDbClient ddb,
                                       String tableName,
                                       String key,
                                       String keyVal,
                                       String name,
                                       String updateVal){

        HashMap<String,AttributeValue> itemKey = new HashMap<String,AttributeValue>();

        itemKey.put(key, AttributeValue.builder().s(keyVal).build());

        HashMap<String,AttributeValueUpdate> updatedValues =
                new HashMap<String,AttributeValueUpdate>();

        // Update the column specified by name with updatedVal
        updatedValues.put(name, AttributeValueUpdate.builder()
                .value(AttributeValue.builder().s(updateVal).build())
                .action(AttributeAction.PUT)
                .build());

        UpdateItemRequest request = UpdateItemRequest.builder()
                .tableName(tableName)
                .key(itemKey)
                .attributeUpdates(updatedValues)
                .build();

        try {
            ddb.updateItem(request);
        } catch (ResourceNotFoundException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }

        System.out.println("Done!");
    }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateItem.java) di GitHub.

## Menghapus item yang ada dalam tabel
<a name="dynamodb-delete-item"></a>

Anda dapat menghapus item yang ada dalam tabel dengan menggunakan `deleteItem` metode dan memberikan nama tabel serta nilai kunci primer. DynamoDbClient

**catatan**  
Jika tabel bernama tidak ada untuk akun dan wilayah Anda, atau jika item yang diidentifikasi oleh kunci utama yang Anda lewati tidak ada, a akan [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)ditampilkan.

 **Impor** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import java.util.HashMap;
```

 **Kode** 

```
  public static void deleteDynamoDBItem(DynamoDbClient ddb, String tableName, String key, String keyVal) {

        HashMap<String,AttributeValue> keyToGet =
                new HashMap<String,AttributeValue>();

        keyToGet.put(key, AttributeValue.builder()
                .s(keyVal)
                .build());

        DeleteItemRequest deleteReq = DeleteItemRequest.builder()
                .tableName(tableName)
                .key(keyToGet)
                .build();

        try {
            ddb.deleteItem(deleteReq);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
```

Lihat [contoh lengkapnya](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteItem.java) di GitHub.

## Informasi selengkapnya
<a name="more-information"></a>
+  [Pedoman untuk Bekerja dengan Item](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/best-practices.html) di Panduan Amazon DynamoDB Pengembang
+  [Bekerja dengan Item DynamoDB di](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/WorkingWithItems.html) Panduan Amazon DynamoDB Pengembang

# Peta objek Java ke item DynamoDB dengan AWS SDK for Java 2.x
<a name="dynamodb-enhanced-client"></a>

[DynamoDB Enhanced Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html) API adalah library tingkat tinggi yang merupakan penerus kelas dalam SDK for `DynamoDBMapper` Java v1.x. Ini menawarkan cara mudah untuk memetakan kelas sisi klien ke tabel DynamoDB. Anda menentukan hubungan antara tabel dan kelas data yang sesuai dalam kode Anda. Setelah menentukan hubungan tersebut, Anda dapat melakukan berbagai operasi buat, baca, perbarui, atau hapus (CRUD) pada tabel atau item di DynamoDB.

DynamoDB Enhanced Client API juga menyertakan API [Dokumen yang Ditingkatkan](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) yang memungkinkan Anda bekerja dengan item tipe dokumen yang tidak mengikuti skema yang ditentukan. 

**Topics**
+ [Memulai menggunakan DynamoDB Enhanced Client API](ddb-en-client-getting-started.md)
+ [Pelajari dasar-dasar DynamoDB Enhanced Client API](ddb-en-client-use.md)
+ [Gunakan fitur pemetaan tingkat lanjut](ddb-en-client-adv-features.md)
+ [Bekerja dengan dokumen JSON dengan Enhanced Document API untuk DynamoDB](ddb-en-client-doc-api.md)
+ [Gunakan ekstensi untuk menyesuaikan operasi DynamoDB Enhanced Client](ddb-en-client-extensions.md)
+ [Gunakan DynamoDB Enhanced Client API secara asinkron](ddb-en-client-async.md)
+ [Anotasi kelas data](ddb-en-client-anno-index.md)

# Memulai menggunakan DynamoDB Enhanced Client API
<a name="ddb-en-client-getting-started"></a>

Tutorial berikut memperkenalkan Anda pada dasar-dasar yang Anda butuhkan untuk bekerja dengan DynamoDB Enhanced Client API.

## Tambahkan dependensi
<a name="ddb-en-client-gs-dep"></a>

Untuk mulai bekerja dengan DynamoDB Enhanced Client API di project Anda, tambahkan dependensi pada artefak Maven. `dynamodb-enhanced` Ini ditunjukkan dalam contoh berikut. 

------
#### [ Maven ]

```
<project>
  <dependencyManagement>
   <dependencies>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>bom</artifactId>
        <version><VERSION></version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
   </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>dynamodb-enhanced</artifactId>
    </dependency>
  </dependencies>
  ...
</project>
```

Lakukan pencarian repositori pusat Maven untuk [versi terbaru](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) dan ganti *<VERSION>* dengan nilai ini.

------
#### [ Gradle ]

```
repositories {
    mavenCentral()
}
dependencies {
    implementation(platform("software.amazon.awssdk:bom:<VERSION>"))
    implementation("software.amazon.awssdk:dynamodb-enhanced")
    ...
}
```

Lakukan pencarian repositori pusat Maven untuk [versi terbaru](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) dan ganti *<VERSION>* dengan nilai ini.

------

# Menghasilkan `TableSchema` dari kelas data
<a name="ddb-en-client-gs-tableschema"></a>

A `[TableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableSchema.html)` memungkinkan klien yang disempurnakan untuk memetakan nilai atribut DynamoDB ke dan dari kelas sisi klien Anda. Dalam tutorial ini, Anda belajar tentang `TableSchema` s yang berasal dari kelas data statis dan dihasilkan dari kode dengan menggunakan pembangun.

## Gunakan kelas data beranotasi
<a name="ddb-en-client-gs-tableschema-anno-bean"></a>

SDK for Java 2.x menyertakan [serangkaian anotasi](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/package-summary.html) yang dapat Anda gunakan dengan kelas data untuk menghasilkan `TableSchema` cepat untuk memetakan kelas Anda ke tabel.

Mulailah dengan membuat kelas data yang sesuai dengan [JavaBean spesifikasi](https://download.oracle.com/otn-pub/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/beans.101.pdf). Spesifikasi mensyaratkan bahwa kelas memiliki konstruktor publik tanpa argumen dan memiliki getter dan setter untuk setiap atribut di kelas. Sertakan anotasi tingkat kelas untuk menunjukkan bahwa kelas data adalah a. `DynamoDbBean` Juga, minimal, sertakan `DynamoDbPartitionKey` anotasi pada pengambil atau penyetel untuk atribut kunci utama. 

Anda dapat menerapkan [anotasi tingkat atribut](ddb-en-client-anno-index.md) ke getter atau setter, tetapi tidak keduanya.

**catatan**  
Istilah `property` ini biasanya digunakan untuk nilai yang dienkapsulasi dalam a. JavaBean Namun, panduan ini menggunakan istilah `attribute` sebagai gantinya, agar konsisten dengan terminologi yang digunakan oleh DynamoDB.

`Customer`Kelas berikut menunjukkan anotasi yang menghubungkan definisi kelas ke tabel DynamoDB.

### `Customer` kelas
<a name="ddb-en-client-gs-tableschema-anno-bean-cust"></a>

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

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.time.Instant;

@DynamoDbBean
public class Customer {

    private String id;
    private String name;
    private String email;
    private Instant regDate;

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

    public void setId(String id) { this.id = id; }

    public String getCustName() { return this.name; }

    public void setCustName(String name) { this.name = name; }

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

    public void setEmail(String email) { this.email = email; }

    public Instant getRegistrationDate() { return this.regDate; }

    public void setRegistrationDate(Instant registrationDate) { this.regDate = registrationDate; }

    @Override
    public String toString() {
        return "Customer [id=" + id + ", name=" + name + ", email=" + email
                + ", regDate=" + regDate + "]";
    }
}
```

Setelah Anda membuat kelas data beranotasi, gunakan untuk membuat`TableSchema`, seperti yang ditunjukkan pada cuplikan berikut.

```
static final TableSchema<Customer> customerTableSchema = TableSchema.fromBean(Customer.class);
```

A `TableSchema` dirancang untuk menjadi statis dan tidak dapat diubah. Anda biasanya dapat membuat instance pada waktu pemuatan kelas.

Metode `TableSchema.fromBean()` pabrik statis mengintrospeksi kacang untuk menghasilkan pemetaan atribut kelas data (properti) ke dan dari atribut DynamoDB.

Untuk contoh bekerja dengan model data yang terdiri dari beberapa kelas data, lihat `Person` kelas di [Bekerja dengan atribut yang kacang, peta, daftar, dan set](ddb-en-client-adv-features-nested.md) bagian tersebut.

## Gunakan pembangun
<a name="ddb-en-client-gs-tableschema-builder"></a>

Anda dapat melewatkan biaya introspeksi kacang jika Anda menentukan skema tabel dalam kode. Jika Anda membuat kode skema, kelas Anda tidak perlu mengikuti standar JavaBean penamaan dan juga tidak perlu dianotasi. Contoh berikut menggunakan pembangun dan setara dengan contoh `Customer` kelas yang menggunakan anotasi.

```
static final TableSchema<Customer> customerTableSchema =
                TableSchema.builder(Customer.class)
                        .newItemSupplier(Customer::new)
                        .addAttribute(String.class, a -> a.name("id")
                                .getter(Customer::getId)
                                .setter(Customer::setId)
                                .tags(StaticAttributeTags.primaryPartitionKey()))
                        .addAttribute(String.class, a -> a.name("email")
                                .getter(Customer::getEmail)
                                .setter(Customer::setEmail)
                                .tags(StaticAttributeTags.primarySortKey()))
                        .addAttribute(String.class, a -> a.name("name")
                                .getter(Customer::getCustName)
                                .setter(Customer::setCustName))
                        .addAttribute(Instant.class, a -> a.name("registrationDate")
                                .getter(Customer::getRegistrationDate)
                                .setter(Customer::setRegistrationDate))
                        .build();
```

# Buat klien yang disempurnakan dan `DynamoDbTable`
<a name="ddb-en-client-getting-started-dynamodbTable"></a>

## Buat klien yang disempurnakan
<a name="ddb-en-client-getting-started-dynamodbTable-eclient"></a>

[DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html)Kelas atau rekan asinkron, [DynamoDbEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html), adalah titik masuk untuk bekerja dengan DynamoDB Enhanced Client API.

Klien yang disempurnakan membutuhkan standar `[DynamoDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html)` untuk melakukan pekerjaan. API menawarkan dua cara untuk membuat `DynamoDbEnhancedClient` instance. Opsi pertama, yang ditunjukkan dalam cuplikan berikut, membuat standar `DynamoDbClient` dengan pengaturan default diambil dari pengaturan konfigurasi.

```
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.create();
```

Jika Anda ingin mengonfigurasi klien standar yang mendasarinya, Anda dapat menyediakannya ke metode pembangun klien yang disempurnakan seperti yang ditunjukkan pada cuplikan berikut.

```
// Configure an instance of the standard DynamoDbClient.
DynamoDbClient standardClient = DynamoDbClient.builder()
    .region(Region.US_EAST_1)
    .credentialsProvider(ProfileCredentialsProvider.create())
    .build();

// Use the configured standard client with the enhanced client.
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
    .dynamoDbClient(standardClient)
    .build();
```

## Buat sebuah `DynamoDbTable` instance
<a name="ddb-en-client-getting-started-dynamodbTable-table"></a>

Pikirkan a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)sebagai representasi sisi klien dari tabel DynamoDB yang menggunakan fungsionalitas pemetaan yang disediakan oleh file. `TableSchema` `DynamoDbTable`Kelas menyediakan metode untuk operasi CRUD yang memungkinkan Anda berinteraksi dengan tabel DynamoDB tunggal.

`DynamoDbTable<T>`adalah kelas generik yang mengambil argumen tipe tunggal, apakah itu kelas khusus atau `EnhancedDocument` saat bekerja dengan item tipe dokumen. Jenis argumen ini menetapkan hubungan antara kelas yang Anda gunakan dan tabel DynamoDB tunggal.

Gunakan metode `table()` pabrik `DynamoDbEnhancedClient` untuk membuat `DynamoDbTable` instance seperti yang ditunjukkan pada cuplikan berikut.

```
static final DynamoDbTable<Customer> customerTable = 
        enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
```

`DynamoDbTable`contoh adalah kandidat untuk lajang karena mereka tidak dapat diubah dan dapat digunakan di seluruh aplikasi Anda.

Kode Anda sekarang memiliki representasi dalam memori dari tabel DynamoDB yang dapat bekerja dengan instance. `Customer` Tabel DynamoDB yang sebenarnya mungkin atau mungkin tidak ada. Jika tabel bernama `Customer` sudah ada, Anda dapat mulai melakukan operasi CRUD terhadapnya. Jika tidak ada, gunakan `DynamoDbTable` instance untuk membuat tabel seperti yang dibahas di bagian berikutnya.

# Buat tabel DynamoDB jika diperlukan
<a name="ddb-en-client-gs-ddbtable"></a>

Setelah Anda membuat `DynamoDbTable` instance, gunakan untuk melakukan pembuatan tabel *satu kali* di DynamoDB.

## Buat kode contoh tabel
<a name="ddb-en-client-gs-ddbtable-createex"></a>

Contoh berikut membuat tabel DynamoDB berdasarkan `Customer` kelas data. 

Contoh ini membuat tabel DynamoDB dengan `Customer` nama —identik dengan nama kelas—tetapi nama tabel bisa menjadi sesuatu yang lain. Apa pun nama Anda tabel, Anda harus menggunakan nama ini dalam aplikasi tambahan untuk bekerja dengan tabel. Berikan nama ini ke `table()` metode kapan pun Anda membuat `DynamoDbTable` objek lain agar dapat bekerja dengan tabel DynamoDB yang mendasarinya.

Parameter lambda Java`builder`,, diteruskan ke `createTable` metode memungkinkan Anda [menyesuaikan tabel](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html). Dalam contoh ini, [throughput yang disediakan dikonfigurasi](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.ProvisionedThroughput.Manual). Jika Anda ingin menggunakan pengaturan default saat membuat tabel, lewati pembangun seperti yang ditunjukkan pada cuplikan berikut.

```
customerTable.createTable();
```

Saat pengaturan default digunakan, nilai untuk throughput yang disediakan tidak disetel. Sebagai gantinya, mode penagihan untuk tabel diatur ke [sesuai permintaan](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.OnDemand).

Contoh ini juga menggunakan `[DynamoDbWaiter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/waiters/DynamoDbWaiter.html)` sebelum mencoba untuk mencetak nama tabel yang diterima dalam respon. Pembuatan meja membutuhkan waktu. Oleh karena itu, menggunakan pelayan berarti Anda tidak perlu menulis logika yang melakukan polling layanan DynamoDB untuk melihat apakah tabel ada sebelum menggunakan tabel.

### Impor
<a name="ddb-en-client-gs-ddbtable-imports"></a>

```
import com.example.dynamodb.Customer;
import software.amazon.awssdk.core.internal.waiters.ResponseOrException;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.model.CreateTableEnhancedRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.waiters.DynamoDbWaiter;
```

### Kode
<a name="ddb-en-client-gs-ddbtable-code"></a>

```
 public static void createCustomerTable(DynamoDbTable<Customer> customerTable, DynamoDbClient standardClient) {
     // Create the DynamoDB table using the 'customerTable' DynamoDbTable instance.
     customerTable.createTable(builder -> builder
             .provisionedThroughput(b -> b
                     .readCapacityUnits(10L)
                     .writeCapacityUnits(10L)
                     .build())
     );
     // The DynamoDbClient instance (named 'standardClient') passed to the builder for the DynamoDbWaiter is the same instance
     // that was passed to the builder of the DynamoDbEnhancedClient instance that we created previously.
     // By using the same instance, it ensures that the same Region that was configured on the standard DynamoDbClient 
     // instance is used for other service clients that accept a DynamoDbClient during construction.
     try (DynamoDbWaiter waiter = DynamoDbWaiter.builder().client(standardClient).build()) { // DynamoDbWaiter is Autocloseable
         ResponseOrException<DescribeTableResponse> response = waiter
                 .waitUntilTableExists(builder -> builder.tableName("Customer").build())
                 .matched();
         DescribeTableResponse tableDescription = response.response().orElseThrow(
                 () -> new RuntimeException("Customer table was not created."));
         // The actual error can be inspected in response.exception()
         logger.info("Customer table was created.");
     }
 }
```

**catatan**  
Nama atribut tabel DynamoDB dimulai dengan huruf kecil ketika tabel dihasilkan dari kelas data. Jika Anda ingin nama atribut tabel dimulai dengan huruf besar, gunakan [`@DynamoDbAttribute(NAME)`anotasi](ddb-en-client-adv-features-inex-attr.md) dan berikan nama yang Anda inginkan sebagai parameter.

# Lakukan operasi
<a name="ddb-en-client-gs-use"></a>

Setelah tabel dibuat, gunakan `DynamoDbTable` instance untuk melakukan operasi terhadap tabel DynamoDB. 

Dalam contoh berikut, singleton `DynamoDbTable<Customer>` dilewatkan sebagai parameter bersama dengan contoh [kelas `Customer` data](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) untuk menambahkan item baru ke tabel.

```
    public static void putItemExample(DynamoDbTable<Customer> customerTable, Customer customer){
        logger.info(customer.toString());
        customerTable.putItem(customer);
    }
```

## Objek `Customer`
<a name="perform_ops_create_customer_instatnce"></a>

```
        Customer customer = new Customer();
        customer.setId("1");
        customer.setCustName("Customer Name");
        customer.setEmail("customer@example.com");
        customer.setRegistrationDate(Instant.parse("2023-07-03T10:15:30.00Z"));
```

Sebelum mengirim `customer` objek ke layanan DynamoDB, catat output dari metode objek untuk membandingkannya dengan apa yang dikirim `toString()` klien yang disempurnakan.

```
Customer [id=1, name=Customer Name, email=customer@example.com, regDate=2023-07-03T10:15:30Z]
```

Pencatatan tingkat kabel menunjukkan muatan permintaan yang dihasilkan. Klien yang disempurnakan menghasilkan representasi tingkat rendah dari kelas data. `regDate`Atribut, yang merupakan `Instant` tipe di Java, direpresentasikan sebagai string DynamoDB.

```
{
  "TableName": "Customer",
  "Item": {
    "registrationDate": {
      "S": "2023-07-03T10:15:30Z"
    },
    "id": {
      "S": "1"
    },
    "custName": {
      "S": "Customer Name"
    },
    "email": {
      "S": "customer@example.com"
    }
  }
}
```

# Bekerja dengan tabel yang ada
<a name="ddb-en-client-gs-existingtable"></a>

Bagian sebelumnya menunjukkan cara membuat tabel DynamoDB dimulai dengan kelas data Java. Jika Anda sudah memiliki tabel yang ada dan ingin menggunakan fitur klien yang disempurnakan, Anda dapat membuat kelas data Java untuk bekerja dengan tabel. Anda perlu memeriksa tabel DynamoDB dan menambahkan anotasi yang diperlukan ke kelas data. 

Sebelum Anda bekerja dengan tabel yang ada, panggil `DynamoDbEnhanced.table()` metode. Ini dilakukan pada contoh sebelumnya dengan pernyataan berikut.

```
DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
```

Setelah `DynamoDbTable` instance dikembalikan, Anda dapat mulai bekerja segera dengan tabel yang mendasarinya. Anda tidak perlu membuat ulang tabel dengan memanggil `DynamoDbTable.createTable()` metode.

Contoh berikut menunjukkan ini dengan segera mengambil `Customer` contoh dari tabel DynamoDB.

```
DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
// The Customer table exists already and has an item with a primary key value of "1" and a sort key value of "customer@example.com".
customerTable.getItem(
        Key.builder().
                partitionValue("1").
                sortValue("customer@example.com").build());
```

**penting**  
Nama tabel yang digunakan dalam `table()` metode harus cocok dengan nama tabel DynamoDB yang ada.

# Pelajari dasar-dasar DynamoDB Enhanced Client API
<a name="ddb-en-client-use"></a>

[Topik ini membahas fitur dasar DynamoDB Enhanced Client API dan membandingkannya dengan API klien DynamoDB standar.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html)

Jika Anda baru mengenal DynamoDB Enhanced Client API, kami sarankan Anda melalui tutorial [pengantar](ddb-en-client-getting-started.md) untuk membiasakan diri dengan kelas fundamental.

## item DynamoDB di Java
<a name="ddb-en-client-use-usecase"></a>

Tabel DynamoDB menyimpan item. Bergantung pada kasus penggunaan Anda, item di sisi Java dapat berbentuk data atau struktur terstruktur statis yang dibuat secara dinamis. 

Jika kasus penggunaan Anda memanggil item dengan kumpulan atribut yang konsisten, gunakan [kelas beranotasi](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean) atau gunakan [pembuat](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-builder) untuk menghasilkan tipe statis yang sesuai. `TableSchema` 

Atau, jika Anda perlu menyimpan item yang terdiri dari berbagai struktur, buat`DocumentTableSchema`. `DocumentTableSchema`adalah bagian dari [Enhanced Document API](ddb-en-client-doc-api.md) dan hanya memerlukan kunci primer yang diketik secara statis dan bekerja dengan `EnhancedDocument` instance untuk menyimpan elemen data. Enhanced Document API dibahas dalam [topik lain.](ddb-en-client-doc-api.md)

## Tipe atribut untuk kelas model data
<a name="ddb-en-client-use-types"></a>

Meskipun DynamoDB [mendukung sejumlah kecil tipe atribut](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) dibandingkan dengan sistem tipe kaya Java, DynamoDB Enhanced Client API menyediakan mekanisme untuk mengonversi anggota kelas Java ke dan dari tipe atribut DynamoDB.

Jenis atribut (properti) kelas data Java Anda harus berupa tipe objek, bukan primitif. Misalnya, selalu gunakan `Long` dan `Integer` objek tipe data, bukan `long` dan `int` primitif.

[Secara default, DynamoDB Enhanced Client API mendukung konverter atribut untuk sejumlah besar tipe, [seperti](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html) Integer, String[,](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) dan Instant. [BigDecimal](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/BigDecimalAttributeConverter.html)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/InstantAsStringAttributeConverter.html) Daftar ini muncul di [kelas implementasi AttributeConverter antarmuka yang dikenal](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html). Daftar ini mencakup banyak jenis dan koleksi seperti peta, daftar, dan set.

Untuk menyimpan data untuk jenis atribut yang tidak didukung secara default atau tidak sesuai dengan JavaBean konvensi, Anda dapat menulis `AttributeConverter` implementasi khusus untuk melakukan konversi. Lihat bagian konversi atribut untuk [contoh](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example).

Untuk menyimpan data untuk tipe atribut yang kelasnya sesuai dengan spesifikasi kacang Java (atau [kelas data yang tidak dapat diubah](ddb-en-client-use-immut.md)), Anda dapat mengambil dua pendekatan. 
+ Jika Anda memiliki akses ke file sumber, Anda dapat membuat anotasi kelas dengan `@DynamoDbBean` (atau`@DynamoDbImmutable`). Bagian yang membahas atribut bersarang menunjukkan [contoh](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-anno) penggunaan kelas beranotasi.
+ Jika tidak memiliki akses ke file sumber dari kelas JavaBean data untuk atribut (atau Anda tidak ingin membubuhi keterangan file sumber kelas yang Anda memiliki akses ke), maka Anda dapat menggunakan pendekatan builder. Ini menciptakan skema tabel tanpa mendefinisikan kunci. Kemudian, Anda dapat menyusun skema tabel ini di dalam skema tabel lain untuk melakukan pemetaan. Bagian atribut bersarang memiliki [contoh](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-builder) yang menunjukkan penggunaan skema bersarang.

### Nilai nol
<a name="ddb-en-client-use-types-nulls"></a>

Saat Anda menggunakan `putItem` metode ini, klien yang disempurnakan tidak menyertakan atribut bernilai nol dari objek data yang dipetakan dalam permintaan ke DynamoDB.

Perilaku default SDK untuk `updateItem` permintaan menghapus atribut dari item di DynamoDB yang disetel ke null dalam objek yang Anda kirimkan dalam metode. `updateItem` Jika Anda bermaksud memperbarui beberapa nilai atribut dan menjaga yang lain tidak berubah, Anda memiliki dua opsi.
+ Ambil item (dengan menggunakan`getItem`) sebelum Anda membuat perubahan pada nilai. Dengan menggunakan pendekatan ini, SDK mengirimkan semua nilai yang diperbarui dan lama ke DynamoDB.
+ Gunakan salah satu `[IgnoreNullsMode](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html).SCALAR_ONLY` atau `IgnoreNullsMode.MAPS_ONLY` ketika Anda membuat permintaan untuk memperbarui item. Kedua mode mengabaikan properti bernilai nol dalam objek yang mewakili atribut skalar di DynamoDB. [Perbarui item yang berisi tipe kompleks](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-updates)Topik dalam panduan ini berisi informasi lebih lanjut tentang `IgnoreNullsMode` nilai-nilai dan cara bekerja dengan tipe yang kompleks.

Contoh berikut menunjukkan `ignoreNullsMode()` untuk `updateItem()` metode ini.

```
    public static void updateItemNullsExample() {
        Customer customer = new Customer();
        customer.setCustName("CustomerName");
        customer.setEmail("email");
        customer.setId("1");
        customer.setRegistrationDate(Instant.now());

        logger.info("Original customer: {}", customer);

        // Put item with values for all attributes.
        try {
            customerAsyncDynamoDbTable.putItem(customer).join();
        } catch (RuntimeException rte) {
            logger.error("A exception occurred during putItem: {}", rte.getCause().getMessage(), rte);
            return;
        }

        // Create a Customer instance with the same 'id' and 'email' values, but a different 'name' value.
        // Do not set the 'registrationDate' attribute.
        Customer customerForUpdate = new Customer();
        customerForUpdate.setCustName("NewName");
        customerForUpdate.setEmail("email");
        customerForUpdate.setId("1");

        // Update item without setting the 'registrationDate' property and set IgnoreNullsMode to SCALAR_ONLY.
        try {
            Customer updatedWithNullsIgnored = customerAsyncDynamoDbTable.updateItem(b -> b
                            .item(customerForUpdate)
                            .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY))
                    .join();
            logger.info("Customer updated with nulls ignored: {}", updatedWithNullsIgnored.toString());
        } catch (RuntimeException rte) {
            logger.error("An exception occurred during updateItem: {}", rte.getCause().getMessage(), rte);
            return;
        }

        // Update item without setting the registrationDate attribute and not setting ignoreNulls to true.
        try {
            Customer updatedWithNullsUsed = customerAsyncDynamoDbTable.updateItem(customerForUpdate)
                    .join();
            logger.info("Customer updated with nulls used: {}", updatedWithNullsUsed.toString());
        } catch (RuntimeException rte) {
            logger.error("An exception occurred during updateItem: {}", rte.getCause().getMessage(), rte);
        }
    }


// Logged lines. 
Original customer: Customer [id=1, name=CustomerName, email=email, regDate=2024-10-11T14:12:30.222858Z]
Customer updated with nulls ignored: Customer [id=1, name=NewName, email=email, regDate=2024-10-11T14:12:30.222858Z]
Customer updated with nulls used: Customer [id=1, name=NewName, email=email, regDate=null]
```

## Metode dasar DynamoDB Enhanced Client
<a name="ddb-en-client-use-basic-ops"></a>

Metode dasar peta klien yang disempurnakan ke operasi layanan DynamoDB yang dinamai menurut namanya. Contoh berikut menunjukkan variasi paling sederhana dari setiap metode. Anda dapat menyesuaikan setiap metode dengan meneruskan objek permintaan yang disempurnakan. Objek permintaan yang disempurnakan menawarkan sebagian besar fitur yang tersedia di klien DynamoDB standar. Mereka sepenuhnya didokumentasikan dalam Referensi AWS SDK for Java 2.x API.

Contoh menggunakan yang [`Customer` kelas](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) ditunjukkan sebelumnya.

```
// CreateTable
customerTable.createTable();

// GetItem
Customer customer = customerTable.getItem(Key.builder().partitionValue("a123").build());

// UpdateItem
Customer updatedCustomer = customerTable.updateItem(customer);

// PutItem
customerTable.putItem(customer);

// DeleteItem
Customer deletedCustomer = customerTable.deleteItem(Key.builder().partitionValue("a123").sortValue(456).build());

// Query
PageIterable<Customer> customers = customerTable.query(keyEqualTo(k -> k.partitionValue("a123")));

// Scan
PageIterable<Customer> customers = customerTable.scan();

// BatchGetItem
BatchGetResultPageIterable batchResults = 
    enhancedClient.batchGetItem(r -> r.addReadBatch(ReadBatch.builder(Customer.class)
                                      .mappedTableResource(customerTable)
                                      .addGetItem(key1)
                                      .addGetItem(key2)
                                      .addGetItem(key3)
                                      .build()));

// BatchWriteItem
batchResults = enhancedClient.batchWriteItem(r -> r.addWriteBatch(WriteBatch.builder(Customer.class)
                                                   .mappedTableResource(customerTable)
                                                   .addPutItem(customer)
                                                   .addDeleteItem(key1)
                                                   .addDeleteItem(key1)
                                                   .build()));

// TransactGetItems
transactResults = enhancedClient.transactGetItems(r -> r.addGetItem(customerTable, key1)
                                                        .addGetItem(customerTable, key2));

// TransactWriteItems
enhancedClient.transactWriteItems(r -> r.addConditionCheck(customerTable, 
                                                           i -> i.key(orderKey)
                                                                 .conditionExpression(conditionExpression))
                                        .addUpdateItem(customerTable, customer)
                                        .addDeleteItem(customerTable, key));
```

## Bandingkan DynamoDB Enhanced Client dengan klien DynamoDB standar
<a name="ddb-en-client-use-compare"></a>

Baik APIs klien DynamoDB [- standar [dan](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html) ditingkatkan -](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html) memungkinkan Anda bekerja dengan tabel DynamoDB untuk melakukan operasi tingkat data CRUD (membuat, membaca, memperbarui, dan menghapus). Perbedaan antara klien APIs adalah bagaimana hal itu dicapai. Menggunakan klien standar, Anda bekerja secara langsung dengan atribut data tingkat rendah. API klien yang disempurnakan menggunakan kelas Java yang sudah dikenal dan memetakan ke API tingkat rendah di belakang layar.

Sementara kedua klien APIs mendukung operasi tingkat data, klien DynamoDB standar juga mendukung operasi tingkat sumber daya. Operasi tingkat sumber daya mengelola database, seperti membuat cadangan, daftar tabel, dan memperbarui tabel. API klien yang disempurnakan mendukung sejumlah operasi tingkat sumber daya tertentu seperti membuat, mendeskripsikan, dan menghapus tabel.

Untuk mengilustrasikan pendekatan berbeda yang digunakan oleh dua klien APIs, contoh kode berikut menunjukkan pembuatan `ProductCatalog` tabel yang sama menggunakan klien standar dan klien yang disempurnakan.

### Bandingkan: Buat tabel menggunakan klien DynamoDB standar
<a name="ddb-en-client-use-compare-cs1"></a>

```
DependencyFactory.dynamoDbClient().createTable(builder -> builder
        .tableName(TABLE_NAME)
        .attributeDefinitions(
                b -> b.attributeName("id").attributeType(ScalarAttributeType.N),
                b -> b.attributeName("title").attributeType(ScalarAttributeType.S),
                b -> b.attributeName("isbn").attributeType(ScalarAttributeType.S)
        )
        .keySchema(
                builder1 -> builder1.attributeName("id").keyType(KeyType.HASH),
                builder2 -> builder2.attributeName("title").keyType(KeyType.RANGE)
        )
        .globalSecondaryIndexes(builder3 -> builder3
                        .indexName("products_by_isbn")
                        .keySchema(builder2 -> builder2
                                .attributeName("isbn").keyType(KeyType.HASH))
                        .projection(builder2 -> builder2
                                .projectionType(ProjectionType.INCLUDE)
                                .nonKeyAttributes("price", "authors"))
                        .provisionedThroughput(builder4 -> builder4
                                .writeCapacityUnits(5L).readCapacityUnits(5L))
        )
        .provisionedThroughput(builder1 -> builder1
                .readCapacityUnits(5L).writeCapacityUnits(5L))
);
```

### Bandingkan: Buat tabel menggunakan DynamoDB Enhanced Client
<a name="ddb-en-client-use-compare-cs2"></a>

```
DynamoDbEnhancedClient enhancedClient = DependencyFactory.enhancedClient();
productCatalog = enhancedClient.table(TABLE_NAME, TableSchema.fromImmutableClass(ProductCatalog.class));
productCatalog.createTable(b -> b
        .provisionedThroughput(b1 -> b1.readCapacityUnits(5L).writeCapacityUnits(5L))
        .globalSecondaryIndices(b2 -> b2.indexName("products_by_isbn")
                .projection(b4 -> b4
                        .projectionType(ProjectionType.INCLUDE)
                        .nonKeyAttributes("price", "authors"))
                .provisionedThroughput(b3 -> b3.writeCapacityUnits(5L).readCapacityUnits(5L))
        )
);
```

Klien yang disempurnakan menggunakan kelas data beranotasi berikut. DynamoDB Enhanced Client memetakan tipe data Java ke tipe data DynamoDB untuk kode verbose yang lebih sedikit yang lebih mudah diikuti. `ProductCatalog`adalah contoh menggunakan kelas yang tidak dapat diubah dengan DynamoDB Enhanced Client. Penggunaan kelas Immutable untuk kelas data yang dipetakan [dibahas nanti dalam topik](ddb-en-client-use-immut.md) ini.

### `ProductCatalog` kelas
<a name="ddb-en-client-use-compare-cs3"></a>

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

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbIgnore;
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.DynamoDbSortKey;

import java.math.BigDecimal;
import java.util.Objects;
import java.util.Set;

@DynamoDbImmutable(builder = ProductCatalog.Builder.class)
public class ProductCatalog implements Comparable<ProductCatalog> {
    private Integer id;
    private String title;
    private String isbn;
    private Set<String> authors;
    private BigDecimal price;


    private ProductCatalog(Builder builder){
        this.authors = builder.authors;
        this.id = builder.id;
        this.isbn = builder.isbn;
        this.price = builder.price;
        this.title = builder.title;
    }

    public static Builder builder(){ return new Builder(); }

    @DynamoDbPartitionKey
    public Integer id() { return id; }
    
    @DynamoDbSortKey
    public String title() { return title; }
    
    @DynamoDbSecondaryPartitionKey(indexNames = "products_by_isbn")
    public String isbn() { return isbn; }
    public Set<String> authors() { return authors; }
    public BigDecimal price() { return price; }


    public static final class Builder {
      private Integer id;
      private String title;
      private String isbn;
      private Set<String> authors;
      private BigDecimal price;
      private Builder(){}

      public Builder id(Integer id) { this.id = id; return this; }
      public Builder title(String title) { this.title = title; return this; }
      public Builder isbn(String ISBN) { this.isbn = ISBN; return this; }
      public Builder authors(Set<String> authors) { this.authors = authors; return this; }
      public Builder price(BigDecimal price) { this.price = price; return this; }
      public ProductCatalog build() { return new ProductCatalog(this); }
  }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("ProductCatalog{");
        sb.append("id=").append(id);
        sb.append(", title='").append(title).append('\'');
        sb.append(", isbn='").append(isbn).append('\'');
        sb.append(", authors=").append(authors);
        sb.append(", price=").append(price);
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ProductCatalog that = (ProductCatalog) o;
        return id.equals(that.id) && title.equals(that.title) && Objects.equals(isbn, that.isbn) && Objects.equals(authors, that.authors) && Objects.equals(price, that.price);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, title, isbn, authors, price);
    }

    @Override
    @DynamoDbIgnore
    public int compareTo(ProductCatalog other) {
        if (this.id.compareTo(other.id) != 0){
            return this.id.compareTo(other.id);
        } else {
            return this.title.compareTo(other.title);
        }
    }
}
```

Dua contoh kode berikut dari penulisan batch menggambarkan verboseness dan kurangnya keamanan tipe saat menggunakan klien standar sebagai lawan dari klien yang ditingkatkan.

### Bandingkan: Batch write menggunakan klien DynamoDB standar
<a name="ddb-en-client-use-compare-cs4"></a>

```
    public static void batchWriteStandard(DynamoDbClient dynamoDbClient, String tableName) {

        Map<String, AttributeValue> catalogItem = Map.of(
                "authors", AttributeValue.builder().ss("a", "b").build(),
                "id", AttributeValue.builder().n("1").build(),
                "isbn", AttributeValue.builder().s("1-565-85698").build(),
                "title", AttributeValue.builder().s("Title 1").build(),
                "price", AttributeValue.builder().n("52.13").build());

        Map<String, AttributeValue> catalogItem2 = Map.of(
                "authors", AttributeValue.builder().ss("a", "b", "c").build(),
                "id", AttributeValue.builder().n("2").build(),
                "isbn", AttributeValue.builder().s("1-208-98073").build(),
                "title", AttributeValue.builder().s("Title 2").build(),
                "price", AttributeValue.builder().n("21.99").build());

        Map<String, AttributeValue> catalogItem3 = Map.of(
                "authors", AttributeValue.builder().ss("g", "k", "c").build(),
                "id", AttributeValue.builder().n("3").build(),
                "isbn", AttributeValue.builder().s("7-236-98618").build(),
                "title", AttributeValue.builder().s("Title 3").build(),
                "price", AttributeValue.builder().n("42.00").build());

        Set<WriteRequest> writeRequests = Set.of(
                WriteRequest.builder().putRequest(b -> b.item(catalogItem)).build(),
                WriteRequest.builder().putRequest(b -> b.item(catalogItem2)).build(),
                WriteRequest.builder().putRequest(b -> b.item(catalogItem3)).build());

        Map<String, Set<WriteRequest>> productCatalogItems = Map.of(
                "ProductCatalog", writeRequests);

        BatchWriteItemResponse response = dynamoDbClient.batchWriteItem(b -> b.requestItems(productCatalogItems));

        logger.info("Unprocessed items: " + response.unprocessedItems().size());
    }
```

### Bandingkan: Batch write menggunakan DynamoDB Enhanced Client
<a name="ddb-en-client-use-compare-cs5"></a>

```
    public static void batchWriteEnhanced(DynamoDbTable<ProductCatalog> productCatalog) {
        ProductCatalog prod = ProductCatalog.builder()
                .id(1)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(52.13))
                .title("Title 1")
                .build();
        ProductCatalog prod2 = ProductCatalog.builder()
                .id(2)
                .isbn("1-208-98073")
                .authors(new HashSet<>(Arrays.asList("a", "b", "c")))
                .price(BigDecimal.valueOf(21.99))
                .title("Title 2")
                .build();
        ProductCatalog prod3 = ProductCatalog.builder()
                .id(3)
                .isbn("7-236-98618")
                .authors(new HashSet<>(Arrays.asList("g", "k", "c")))
                .price(BigDecimal.valueOf(42.00))
                .title("Title 3")
                .build();

        BatchWriteResult batchWriteResult = DependencyFactory.enhancedClient()
                .batchWriteItem(b -> b.writeBatches(
                        WriteBatch.builder(ProductCatalog.class)
                                .mappedTableResource(productCatalog)
                                .addPutItem(prod).addPutItem(prod2).addPutItem(prod3)
                                .build()
                ));
        logger.info("Unprocessed items: " + batchWriteResult.unprocessedPutItemsForTable(productCatalog).size());
    }
```

# Bekerja dengan kelas data yang tidak dapat diubah
<a name="ddb-en-client-use-immut"></a>

Fitur pemetaan DynamoDB Enhanced Client API bekerja dengan kelas data yang tidak dapat diubah. Kelas yang tidak dapat diubah hanya memiliki getter dan memerlukan kelas pembangun yang digunakan SDK untuk membuat instance kelas. Alih-alih menggunakan `@DynamoDbBean` anotasi seperti yang ditunjukkan di [kelas Pelanggan, kelas](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) yang tidak dapat diubah menggunakan `@DynamoDbImmutable` anotasi, yang mengambil parameter yang menunjukkan kelas pembuat untuk digunakan.

Kelas berikut adalah versi yang tidak dapat diubah dari. `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); }
    }
}
```

Anda harus memenuhi persyaratan berikut ketika Anda membuat anotasi kelas data dengan. `@DynamoDbImmutable`

1. Setiap metode yang keduanya bukan penggantian `Object.class` dan belum dianotasi `@DynamoDbIgnore` harus menjadi pengambil untuk atribut tabel DynamoDB.

1. Setiap pengambil harus memiliki penyetel case-sensitive yang sesuai pada kelas builder.

1. Hanya satu dari kondisi konstruksi berikut yang harus dipenuhi.
   + Kelas builder harus memiliki konstruktor default publik.
   + Kelas data harus memiliki metode statis publik bernama `builder()` yang tidak mengambil parameter dan mengembalikan instance dari kelas builder. Opsi ini ditampilkan di kelas yang tidak dapat diubah`Customer`.

1.  Kelas builder harus memiliki metode publik bernama `build()` yang tidak mengambil parameter dan mengembalikan instance dari kelas yang tidak dapat diubah. 

Untuk membuat `TableSchema` untuk kelas abadi Anda, gunakan `fromImmutableClass()` metode pada `TableSchema` seperti yang ditunjukkan dalam cuplikan berikut.

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

Sama seperti Anda dapat membuat tabel DynamoDB dari kelas yang bisa berubah, Anda dapat membuatnya dari kelas yang tidak dapat diubah dengan panggilan satu kali ke dari seperti *yang ditunjukkan dalam* contoh `createTable()` cuplikan berikut`DynamoDbTable`.

```
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));
}
```

## Gunakan perpustakaan pihak ketiga, seperti Lombok
<a name="ddb-en-client-use-immut-lombok"></a>

Perpustakaan pihak ketiga, seperti [Project Lombok](https://projectlombok.org/), membantu menghasilkan kode boilerplate yang terkait dengan objek yang tidak dapat diubah. DynamoDB Enhanced Client API bekerja dengan pustaka ini selama kelas data mengikuti konvensi yang dirinci di bagian ini. 

Contoh berikut menunjukkan `CustomerImmutable` kelas abadi dengan anotasi Lombok. Perhatikan bagaimana `onMethod` fitur Lombok menyalin anotasi DynamoDB berbasis atribut, seperti, ke kode yang dihasilkan. `@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;
}
```

# Gunakan ekspresi dan kondisi
<a name="ddb-en-client-expressions"></a>

[Ekspresi dalam DynamoDB Enhanced Client API adalah representasi Java dari ekspresi DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html)

DynamoDB Enhanced Client API menggunakan tiga jenis ekspresi:

[Ekspresi](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)  
`Expression`Kelas digunakan ketika Anda menentukan kondisi dan filter.

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html)  
Jenis ekspresi ini merupakan [kondisi utama](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions) untuk operasi kueri.

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html)  
Kelas ini membantu Anda menulis ekspresi [pembaruan DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html) dan saat ini digunakan dalam kerangka ekstensi saat Anda memperbarui item.

## Anatomi ekspresi
<a name="ddb-en-client-expressions-compoonents"></a>

Ekspresi terdiri dari yang berikut:
+ Ekspresi string (wajib). String berisi ekspresi logika DynamoDB dengan nama placeholder untuk nama atribut dan nilai atribut.
+ Peta nilai ekspresi (biasanya diperlukan).
+ Peta nama ekspresi (opsional).

Gunakan pembangun untuk menghasilkan `Expression` objek yang mengambil bentuk umum berikut.

```
Expression expression = Expression.builder()
                            .expression(<String>)
                            .expressionNames(<Map>)
                            .expressionValues(<Map>)
                           .build()
```

`Expression`S biasanya membutuhkan peta nilai ekspresi. Peta memberikan nilai untuk placeholder dalam ekspresi string. Kunci peta terdiri dari nama placeholder yang didahului dengan titik dua (`:`) dan nilai peta adalah instance dari. [AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html) [AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/AttributeValues.html)Kelas memiliki metode kenyamanan untuk menghasilkan `AttributeValue` instance dari literal. Atau, Anda dapat menggunakan `AttributeValue.Builder` untuk menghasilkan `AttributeValue` instance.

Cuplikan berikut menunjukkan peta dengan dua entri setelah baris komentar 2. String diteruskan ke `expression()` metode, ditampilkan setelah baris komentar 1, berisi placeholder yang DynamoDB menyelesaikan sebelum melakukan operasi. Cuplikan ini tidak berisi peta nama ekspresi, karena *harga* adalah nama atribut yang diizinkan.

```
    public static void scanAsync(DynamoDbAsyncTable productCatalog) {
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                .attributesToProject("id", "title", "authors", "price")
                .filterExpression(Expression.builder()
                        // 1. :min_value and :max_value are placeholders for the values provided by the map
                        .expression("price >= :min_value AND price <= :max_value")
                        // 2. Two values are needed for the expression and each is supplied as a map entry.
                        .expressionValues(
                                Map.of( ":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();
```

Jika nama atribut dalam tabel DynamoDB adalah kata cadangan, dimulai dengan angka, atau berisi spasi, peta nama ekspresi diperlukan untuk. `Expression`

Misalnya, jika nama atribut `1price` bukan `price` dalam contoh kode sebelumnya, contoh akan perlu dimodifikasi seperti yang ditunjukkan pada contoh berikut.

```
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .filterExpression(Expression.builder()
                        .expression("#price >= :min_value AND #price <= :max_value")
                        .expressionNames( Map.of("#price", "1price") )
                        .expressionValues(
                                Map.of(":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();
```

Sebuah placeholder untuk nama ekspresi dimulai dengan tanda pound ()`#`. Entri untuk peta nama ekspresi menggunakan placeholder sebagai kunci dan nama atribut sebagai nilai. Peta ditambahkan ke pembuat ekspresi dengan `expressionNames()` metode. DynamoDB menyelesaikan nama atribut sebelum melakukan operasi.

Nilai ekspresi tidak diperlukan jika fungsi digunakan dalam ekspresi string. Contoh fungsi ekspresi adalah`attribute_exists(<attribute_name>)`.

Contoh berikut membangun sebuah `Expression` yang menggunakan fungsi [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions). String ekspresi dalam contoh ini tidak menggunakan placeholder. Ekspresi ini dapat digunakan pada `putItem` operasi untuk memeriksa apakah item sudah ada dalam database dengan nilai `movie` atribut sama dengan `movie` atribut objek data.

```
Expression exp = Expression.builder().expression("attribute_not_exists (movie)").build();
```

Panduan Pengembang DynamoDB berisi informasi lengkap tentang ekspresi [tingkat rendah yang](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html) digunakan dengan DynamoDB.

## Ekspresi kondisi dan kondisional
<a name="ddb-en-client-expressions-cond"></a>

Ketika Anda menggunakan`putItem()`,`updateItem()`, dan `deleteItem()` metode, dan juga ketika Anda menggunakan transaksi dan operasi batch, Anda menggunakan `[Expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)` objek untuk menentukan kondisi yang DynamoDB harus memenuhi untuk melanjutkan operasi. Ekspresi ini diberi nama ekspresi kondisi. Sebagai contoh, lihat ekspresi kondisi yang digunakan dalam `addDeleteItem()` metode (setelah baris komentar 1) dari [contoh transaksi](ddb-en-client-use-multiop-trans.md#ddb-en-client-use-multiop-trans-writeitems-opcondition) yang ditunjukkan dalam panduan ini.

Ketika Anda bekerja dengan `query()` metode, suatu kondisi dinyatakan sebagai a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html). `QueryConditional`Kelas memiliki beberapa metode kenyamanan statis yang membantu Anda menulis kriteria yang menentukan item mana yang akan dibaca dari DynamoDB.

Sebagai contoh`QueryConditionals`, lihat contoh kode pertama dari [`Query`contoh metode](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-query-example) bagian panduan ini.

## Ekspresi Filter
<a name="ddb-en-client-expressions-filter"></a>

Ekspresi filter digunakan dalam operasi pemindaian dan kueri untuk memfilter item yang dikembalikan. 

Ekspresi filter diterapkan setelah semua data dibaca dari database, sehingga biaya baca sama seperti jika tidak ada filter. [Panduan *Pengembang Amazon DynamoDB* memiliki informasi lebih lanjut tentang penggunaan ekspresi filter untuk operasi kueri [dan](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.FilterExpression) pemindaian.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html#Scan.FilterExpression)

Contoh berikut menunjukkan ekspresi filter ditambahkan ke permintaan scan. Kriteria membatasi barang yang dikembalikan ke barang dengan harga antara 8.00 dan 80,00 inklusif.

```
        Map<String, AttributeValue> expressionValues = Map.of(
                ":min_value", numberValue(8.00),
                ":max_value", numberValue(80.00));

        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                // 1. the 'attributesToProject()' method allows you to specify which values you want returned.
                .attributesToProject("id", "title", "authors", "price")
                // 2. Filter expression limits the items returned that match the provided criteria.
                .filterExpression(Expression.builder()
                        .expression("price >= :min_value AND price <= :max_value")
                        .expressionValues(expressionValues)
                        .build())
                .build();
```

## Ekspresi pembaruan
<a name="ddb-en-client-expressions-update"></a>

Metode DynamoDB Enhanced Client `updateItem()` menyediakan cara standar untuk memperbarui item di DynamoDB. [Namun, ketika Anda memerlukan lebih banyak fungsionalitas, [UpdateExpressions](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html)berikan representasi type-safe dari sintaks ekspresi pembaruan DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html) Misalnya, Anda dapat menggunakan `UpdateExpressions` untuk meningkatkan nilai tanpa terlebih dahulu membaca item dari DynamoDB, atau menambahkan anggota individu ke daftar. Ekspresi pembaruan saat ini tersedia di ekstensi khusus untuk `updateItem()` metode ini.

Untuk contoh yang menggunakan ekspresi pembaruan, lihat [contoh ekstensi kustom](ddb-en-client-extensions-custom.md) dalam panduan ini.

Informasi selengkapnya tentang ekspresi pembaruan tersedia di Panduan Pengembang [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html).

# Bekerja dengan hasil paginasi: pemindaian dan kueri
<a name="ddb-en-client-use-multirecord"></a>

*Metode`scan`, `query` dan `batch` metode DynamoDB Enhanced Client API mengembalikan respons dengan satu halaman atau beberapa.* Sebuah halaman berisi satu atau lebih item. Kode Anda dapat memproses respons per halaman atau dapat memproses item individual.

Respons paginasi yang dikembalikan oleh `DynamoDbEnhancedClient` klien sinkron mengembalikan [PageIterable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PageIterable.html)objek, sedangkan respons yang dikembalikan oleh `DynamoDbEnhancedAsyncClient` asinkron mengembalikan objek. [PagePublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PagePublisher.html)

Bagian ini melihat pemrosesan hasil paginasi dan memberikan contoh yang menggunakan pemindaian dan kueri APIs.

## Memindai tabel
<a name="ddb-en-client-use-multirecord-scan"></a>

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer))Metode SDK sesuai dengan operasi [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) dengan nama yang sama. DynamoDB Enhanced Client API menawarkan opsi yang sama tetapi menggunakan model objek yang sudah dikenal dan menangani pagination untuk Anda.

Pertama, kita menjelajahi `PageIterable` antarmuka dengan melihat `scan` metode kelas pemetaan sinkron,. [DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)

### Gunakan API sinkron
<a name="ddb-en-client-use-multirecord-scan-sync"></a>

Contoh berikut menunjukkan `scan` metode yang menggunakan [ekspresi](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html) untuk memfilter item yang dikembalikan. [ProductCatalog](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)Ini adalah objek model yang ditunjukkan sebelumnya.

Ekspresi pemfilteran yang ditampilkan setelah baris komentar 2 membatasi `ProductCatalog` item yang dikembalikan ke item dengan nilai harga antara 8,00 dan 80,00 secara inklusif.

Contoh ini juga mengecualikan `isbn` nilai dengan menggunakan `attributesToProject` metode yang ditampilkan setelah baris komentar 1.

Setelah komentar baris 3, `PageIterable` objek`pagedResults`,, dikembalikan oleh `scan` metode. `stream`Metode `PageIterable` mengembalikan [https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html)objek, yang dapat Anda gunakan untuk memproses halaman. Dalam contoh ini, jumlah halaman dihitung dan dicatat.

Dimulai dengan baris komentar 4, contoh menunjukkan dua variasi mengakses `ProductCatalog` item. Versi setelah baris komentar 4a mengalir melalui setiap halaman dan mengurutkan dan mencatat item di setiap halaman. Versi setelah baris komentar 4b melewatkan iterasi halaman dan mengakses item secara langsung.

`PageIterable`Antarmuka menawarkan beberapa cara untuk memproses hasil karena dua antarmuka induknya— [https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html)dan [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html). `Iterable`membawa`forEach`, `iterator` dan `spliterator` metode, dan `SdkIterable` membawa `stream` metode.

```
    public static void scanSync(DynamoDbTable<ProductCatalog> productCatalog) {

        Map<String, AttributeValue> expressionValues = Map.of(
                ":min_value", numberValue(8.00),
                ":max_value", numberValue(80.00));

        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                // 1. the 'attributesToProject()' method allows you to specify which values you want returned.
                .attributesToProject("id", "title", "authors", "price")
                // 2. Filter expression limits the items returned that match the provided criteria.
                .filterExpression(Expression.builder()
                        .expression("price >= :min_value AND price <= :max_value")
                        .expressionValues(expressionValues)
                        .build())
                .build();

        // 3. A PageIterable object is returned by the scan method.
        PageIterable<ProductCatalog> pagedResults = productCatalog.scan(request);
        logger.info("page count: {}", pagedResults.stream().count());

        // 4. Log the returned ProductCatalog items using two variations.
        // 4a. This version sorts and logs the items of each page.
        pagedResults.stream().forEach(p -> p.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                ));
        // 4b. This version sorts and logs all items for all pages.
        pagedResults.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                );
    }
```

### Gunakan API asinkron
<a name="ddb-en-client-use-multirecord-scan-async"></a>

`scan`Metode asinkron mengembalikan hasil sebagai objek. `PagePublisher` `PagePublisher`Antarmuka memiliki dua `subscribe` metode yang dapat Anda gunakan untuk memproses halaman respons. Salah satu `subscribe` metode berasal dari antarmuka `org.reactivestreams.Publisher` induk. Untuk memproses halaman menggunakan opsi pertama ini, berikan `[Subscriber](https://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html)` instance ke `subscribe` metode. Contoh pertama yang berikut menunjukkan penggunaan `subscribe` metode.

`subscribe`Metode kedua berasal dari [SdkPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)antarmuka. Versi ini `subscribe` menerima [https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html](https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html)bukan a`Subscriber`. Variasi `subscribe` metode ini ditunjukkan pada contoh kedua berikut.

Contoh berikut menunjukkan versi asinkron dari `scan` metode yang menggunakan ekspresi filter yang sama yang ditunjukkan pada contoh sebelumnya. 

Setelah baris komentar 3, `DynamoDbAsyncTable.scan` mengembalikan `PagePublisher` objek. Pada baris berikutnya, kode membuat instance `org.reactivestreams.Subscriber` antarmuka,`ProductCatalogSubscriber`, yang berlangganan baris `PagePublisher` setelah komentar 4.

`Subscriber`Objek mengumpulkan `ProductCatalog` item dari setiap halaman dalam `onNext` metode setelah baris komentar 8 dalam contoh `ProductCatalogSubscriber` kelas. Item disimpan dalam `List` variabel pribadi dan diakses dalam kode panggilan dengan `ProductCatalogSubscriber.getSubscribedItems()` metode. Ini disebut setelah baris komentar 5.

Setelah daftar diambil, kode mengurutkan semua `ProductCatalog` item berdasarkan harga dan mencatat setiap item.

[CountDownLatch](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)Di `ProductCatalogSubscriber` kelas memblokir thread panggilan sampai semua item telah ditambahkan ke daftar sebelum melanjutkan setelah baris komentar 5. 

```
    public static void scanAsync(DynamoDbAsyncTable productCatalog) {
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                .attributesToProject("id", "title", "authors", "price")
                .filterExpression(Expression.builder()
                        // 1. :min_value and :max_value are placeholders for the values provided by the map
                        .expression("price >= :min_value AND price <= :max_value")
                        // 2. Two values are needed for the expression and each is supplied as a map entry.
                        .expressionValues(
                                Map.of( ":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();

        // 3. A PagePublisher object is returned by the scan method.
        PagePublisher<ProductCatalog> pagePublisher = productCatalog.scan(request);
        ProductCatalogSubscriber subscriber = new ProductCatalogSubscriber();
        // 4. Subscribe the ProductCatalogSubscriber to the PagePublisher.
        pagePublisher.subscribe(subscriber);
        // 5. Retrieve all collected ProductCatalog items accumulated by the subscriber.
        subscriber.getSubscribedItems().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(item ->
                        logger.info(item.toString()));
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
    }
```

```
    private static class ProductCatalogSubscriber implements Subscriber<Page<ProductCatalog>> {
        private CountDownLatch latch = new CountDownLatch(1);
        private Subscription subscription;
        private List<ProductCatalog> itemsFromAllPages = new ArrayList<>();

        @Override
        public void onSubscribe(Subscription sub) {
            subscription = sub;
            subscription.request(1L);
            try {
                latch.await(); // Called by main thread blocking it until latch is released.
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void onNext(Page<ProductCatalog> productCatalogPage) {
            // 8. Collect all the ProductCatalog instances in the page, then ask the publisher for one more page.
            itemsFromAllPages.addAll(productCatalogPage.items());
            subscription.request(1L);
        }

        @Override
        public void onError(Throwable throwable) {
        }

        @Override
        public void onComplete() {
            latch.countDown(); // Call by subscription thread; latch releases.
        }

        List<ProductCatalog> getSubscribedItems() {
            return this.itemsFromAllPages;
        }
    }
```

Contoh cuplikan berikut menggunakan versi `PagePublisher.subscribe` metode yang menerima baris `Consumer` setelah komentar 6. Parameter lambda Java mengkonsumsi halaman, yang selanjutnya memproses setiap item. Dalam contoh ini, setiap halaman diproses dan item pada setiap halaman diurutkan dan kemudian dicatat.

```
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

`items`Metode `PagePublisher` membuka bungkus contoh model sehingga kode Anda dapat memproses item secara langsung. Pendekatan ini ditunjukkan dalam cuplikan berikut.

```
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

## Mengkueri Tabel
<a name="ddb-en-client-use-multirecord-query"></a>

Anda dapat menggunakan DynamoDB Enhanced Client untuk menanyakan tabel Anda dan mengambil beberapa item yang cocok dengan kriteria tertentu. [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest))Metode ini menemukan item berdasarkan nilai kunci primer menggunakan `@DynamoDbPartitionKey` dan `@DynamoDbSortKey` anotasi opsional yang ditentukan pada kelas data Anda.

`query()`Metode ini memerlukan nilai kunci partisi dan secara opsional menerima kondisi kunci pengurutan untuk lebih menyempurnakan hasil. Seperti `scan` API, kueri mengembalikan a `PageIterable` untuk panggilan sinkron dan a `PagePublisher` untuk panggilan asinkron.

### `Query`contoh metode
<a name="ddb-en-client-use-multirecord-query-example"></a>

Contoh kode `query()` metode yang mengikuti menggunakan `MovieActor` kelas. Kelas data mendefinisikan kunci primer komposit yang terdiri dari **`movie`**atribut sebagai kunci partisi dan **`actor`**atribut sebagai kunci pengurutan. 

#### `MovieActor` kelas
<a name="ddb-en-client-use-movieactor-class"></a>

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

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
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.util.Objects;

@DynamoDbBean
public class MovieActor implements Comparable<MovieActor> {

    private String movieName;
    private String actorName;
    private String actingAward;
    private Integer actingYear;
    private String actingSchoolName;

    @DynamoDbPartitionKey
    @DynamoDbAttribute("movie")
    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    @DynamoDbSortKey
    @DynamoDbAttribute("actor")
    public String getActorName() {
        return actorName;
    }

    public void setActorName(String actorName) {
        this.actorName = actorName;
    }

    @DynamoDbSecondaryPartitionKey(indexNames = "acting_award_year")
    @DynamoDbAttribute("actingaward")
    public String getActingAward() {
        return actingAward;
    }

    public void setActingAward(String actingAward) {
        this.actingAward = actingAward;
    }

    @DynamoDbSecondarySortKey(indexNames = {"acting_award_year", "movie_year"})
    @DynamoDbAttribute("actingyear")
    public Integer getActingYear() {
        return actingYear;
    }

    public void setActingYear(Integer actingYear) {
        this.actingYear = actingYear;
    }

    @DynamoDbAttribute("actingschoolname")
    public String getActingSchoolName() {
        return actingSchoolName;
    }

    public void setActingSchoolName(String actingSchoolName) {
        this.actingSchoolName = actingSchoolName;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("MovieActor{");
        sb.append("movieName='").append(movieName).append('\'');
        sb.append(", actorName='").append(actorName).append('\'');
        sb.append(", actingAward='").append(actingAward).append('\'');
        sb.append(", actingYear=").append(actingYear);
        sb.append(", actingSchoolName='").append(actingSchoolName).append('\'');
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MovieActor that = (MovieActor) o;
        return Objects.equals(movieName, that.movieName) && Objects.equals(actorName, that.actorName) && Objects.equals(actingAward, that.actingAward) && Objects.equals(actingYear, that.actingYear) && Objects.equals(actingSchoolName, that.actingSchoolName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(movieName, actorName, actingAward, actingYear, actingSchoolName);
    }

    @Override
    public int compareTo(MovieActor o) {
        if (this.movieName.compareTo(o.movieName) != 0){
            return this.movieName.compareTo(o.movieName);
        } else {
            return this.actorName.compareTo(o.actorName);
        }
    }
}
```

Contoh kode yang mengikuti kueri terhadap item berikut.

#### Item dalam `MovieActor` tabel
<a name="ddb-en-client-use-movieactor-items"></a>

```
MovieActor{movieName='movie01', actorName='actor0', actingAward='actingaward0', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
MovieActor{movieName='movie02', actorName='actor0', actingAward='actingaward0', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor1', actingAward='actingaward1', actingYear=2002, actingSchoolName='actingschool1'}
MovieActor{movieName='movie02', actorName='actor2', actingAward='actingaward2', actingYear=2002, actingSchoolName='actingschool2'}
MovieActor{movieName='movie02', actorName='actor3', actingAward='actingaward3', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor4', actingAward='actingaward4', actingYear=2002, actingSchoolName='actingschool4'}
MovieActor{movieName='movie03', actorName='actor0', actingAward='actingaward0', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor1', actingAward='actingaward1', actingYear=2003, actingSchoolName='actingschool1'}
MovieActor{movieName='movie03', actorName='actor2', actingAward='actingaward2', actingYear=2003, actingSchoolName='actingschool2'}
MovieActor{movieName='movie03', actorName='actor3', actingAward='actingaward3', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor4', actingAward='actingaward4', actingYear=2003, actingSchoolName='actingschool4'}
```

Kode berikut mendefinisikan dua `QueryConditional` contoh: `keyEqual` (setelah baris komentar 1) dan `sortGreaterThanOrEqualTo` (setelah baris komentar 1a).

#### Item kueri dengan kunci partisi
<a name="keyEqual-query-conditional-example"></a>

`keyEqual`Instance mencocokkan item dengan nilai kunci partisi dari **`movie01`**. 

Contoh ini juga mendefinisikan ekspresi filter setelah baris komentar 2 yang menyaring item apa pun yang tidak memiliki **`actingschoolname`**nilai.

`QueryEnhancedRequest`Menggabungkan kondisi kunci dan ekspresi filter untuk kueri.

```
    public static void query(DynamoDbTable movieActorTable) {

        // 1. Define a QueryConditional instance to return items matching a partition value.
        QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b.partitionValue("movie01"));
        // 1a. Define a QueryConditional that adds a sort key criteria to the partition value criteria.
        QueryConditional sortGreaterThanOrEqualTo = QueryConditional.sortGreaterThanOrEqualTo(b -> b.partitionValue("movie01").sortValue("actor2"));
        // 2. Define a filter expression that filters out items whose attribute value is null.
        final Expression filterOutNoActingschoolname = Expression.builder().expression("attribute_exists(actingschoolname)").build();

        // 3. Build the query request.
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(keyEqual)
                .filterExpression(filterOutNoActingschoolname)
                .build();
        // 4. Perform the query using the "keyEqual" conditional and filter expression.
        PageIterable<MovieActor> pagedResults = movieActorTable.query(tableQuery);
        logger.info("page count: {}", pagedResults.stream().count()); // Log  number of pages.

        pagedResults.items().stream()
                .sorted()
                .forEach(
                        item -> logger.info(item.toString()) // Log the sorted list of items.
                );
```

**Example — Output menggunakan `keyEqual` query kondisional**  
Berikut ini adalah output dari menjalankan metode. Output menampilkan item dengan `movieName` nilai **movie01** dan tidak menampilkan item yang `actingSchoolName` sama dengan. **`null`**  

```
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

#### Item kueri dengan kunci partisi dan kunci sortir
<a name="sort-type-query-conditional-example"></a>

`sortGreaterThanOrEqualTo``QueryConditional`**Menyempurnakan kecocokan kunci partisi (**movie01**) dengan menambahkan kondisi kunci pengurutan untuk nilai yang lebih besar dari atau sama dengan aktor2.**

[`QueryConditional`metode](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) yang dimulai dengan `sort` memerlukan nilai kunci partisi untuk mencocokkan dan selanjutnya menyempurnakan kueri dengan perbandingan berdasarkan nilai kunci sortir. `Sort`dalam nama metode tidak berarti hasilnya diurutkan, tetapi nilai kunci sortir akan digunakan untuk perbandingan.

Dalam cuplikan berikut, kami mengubah permintaan kueri yang ditampilkan sebelumnya setelah baris komentar 3. Cuplikan ini menggantikan kueri “KeyEqual” bersyarat dengan syarat kueri "sortGreaterThanOrEqualTo" yang ditentukan setelah baris komentar 1a. Kode berikut juga menghapus ekspresi filter.

```
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(sortGreaterThanOrEqualTo).build();
```

**Example — Output menggunakan `sortGreaterThanOrEqualTo` query kondisional**  
Output berikut menampilkan hasil dari query. **Kueri mengembalikan item yang memiliki `movieName` nilai sama dengan **movie01** dan hanya item yang memiliki `actorName` nilai yang lebih besar dari atau sama dengan actor2.** Karena kita menghapus filter, query mengembalikan item yang tidak memiliki nilai untuk `actingSchoolName` atribut.  

```
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

# Lakukan operasi batch
<a name="ddb-en-client-use-multiop-batch"></a>

[DynamoDB Enhanced Client API menawarkan dua metode batch [`batchGetItem`, () dan (](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer)))`batchWriteItem`.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchWriteItem(java.util.function.Consumer))

## Contoh `batchGetItem()`
<a name="ddb-en-client-use-multiop-batch-get"></a>

Dengan [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer))metode ini, Anda dapat mengambil hingga 100 item individual di beberapa tabel dalam satu permintaan keseluruhan. Contoh berikut menggunakan kelas [`Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust)dan [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)data yang ditunjukkan sebelumnya.

Dalam contoh setelah baris 1 dan 2, Anda membangun `[ReadBatch](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ReadBatch.html)` objek yang kemudian Anda tambahkan sebagai parameter ke `batchGetItem()` metode setelah baris komentar 3. 

Kode setelah baris komentar 1 membangun batch untuk dibaca dari `Customer` tabel. Kode setelah baris komentar 1a menunjukkan penggunaan `[GetItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/GetItemEnhancedRequest.Builder.html)` pembangun yang mengambil nilai kunci primer dan nilai kunci pengurutan untuk menentukan item yang akan dibaca. Jika kelas data memiliki kunci komposit, Anda harus memberikan nilai kunci partisi dan nilai kunci sortir. 

Berbeda dengan menentukan nilai kunci untuk meminta item, Anda dapat menggunakan kelas data untuk meminta item seperti yang ditunjukkan setelah baris komentar 1b. SDK mengekstrak nilai kunci di balik layar sebelum mengirimkan permintaan.

[Saat Anda menentukan item menggunakan pendekatan berbasis kunci seperti yang ditunjukkan dalam dua pernyataan setelah 2a, Anda juga dapat menentukan bahwa DynamoDB harus melakukan pembacaan yang sangat konsisten.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html) Ketika `consistentRead()` metode ini digunakan, itu harus digunakan pada semua item yang diminta untuk tabel yang sama.

Untuk mengambil item yang DynamoDB temukan, gunakan metode `[resultsForTable() ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#resultsForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` yang ditampilkan setelah baris komentar 4. Panggil metode untuk setiap tabel yang dibaca dalam permintaan. `resultsForTable()`mengembalikan daftar item yang ditemukan yang dapat Anda proses menggunakan `java.util.List` metode apapun. Contoh ini mencatat setiap item.

Untuk menemukan item yang DynamoDB tidak memproses, gunakan pendekatan setelah baris komentar 5. `BatchGetResultPage`Kelas memiliki `[unprocessedKeysForTable()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#unprocessedKeysForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` metode yang memberi Anda akses ke setiap kunci yang belum diproses. [Referensi BatchGetItem API](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html) memiliki informasi lebih lanjut tentang situasi yang menghasilkan item yang tidak diproses.

```
    public static void batchGetItemExample(DynamoDbEnhancedClient enhancedClient,
                                           DynamoDbTable<Customer> customerTable,
                                           DynamoDbTable<MovieActor> movieActorTable) {

        Customer customer2 = new Customer();
        customer2.setId("2");
        customer2.setEmail("cust2@example.org");

        // 1. Build a batch to read from the Customer table.
        ReadBatch customerBatch = ReadBatch.builder(Customer.class)
                .mappedTableResource(customerTable)
                // 1a. Specify the primary key value and sort key value for the item.
                .addGetItem(b -> b.key(k -> k.partitionValue("1").sortValue("cust1@orgname.org")))
                // 1b. Alternatively, supply a data class instances to provide the primary key values.
                .addGetItem(customer2)
                .build();

        // 2. Build a batch to read from the MovieActor table.
        ReadBatch moveActorBatch = ReadBatch.builder(MovieActor.class)
                .mappedTableResource(movieActorTable)
                // 2a. Call consistentRead(Boolean.TRUE) for each item for the same table.
                .addGetItem(b -> b.key(k -> k.partitionValue("movie01").sortValue("actor1")).consistentRead(Boolean.TRUE))
                .addGetItem(b -> b.key(k -> k.partitionValue("movie01").sortValue("actor4")).consistentRead(Boolean.TRUE))
                .build();

        // 3. Add ReadBatch objects to the request.
        BatchGetResultPageIterable resultPages = enhancedClient.batchGetItem(b -> b.readBatches(customerBatch, moveActorBatch));

        // 4. Retrieve the successfully requested items from each table.
        resultPages.resultsForTable(customerTable).forEach(item -> logger.info(item.toString()));
        resultPages.resultsForTable(movieActorTable).forEach(item -> logger.info(item.toString()));

        // 5. Retrieve the keys of the items requested but not processed by the service.
        resultPages.forEach((BatchGetResultPage pageResult) -> {
            pageResult.unprocessedKeysForTable(customerTable).forEach(key -> logger.info("Unprocessed item key: " + key.toString()));
            pageResult.unprocessedKeysForTable(movieActorTable).forEach(key -> logger.info("Unprocessed item key: " + key.toString()));
        });
    }
```

Asumsikan bahwa item berikut ada di dua tabel sebelum menjalankan kode contoh.

### Item dalam tabel
<a name="ddb-en-client-use-multiop-batch-get-tableitems"></a>

```
Customer [id=1, name=CustName1, email=cust1@example.org, regDate=2023-03-31T15:46:27.688Z]
Customer [id=2, name=CustName2, email=cust2@example.org, regDate=2023-03-31T15:46:28.688Z]
Customer [id=3, name=CustName3, email=cust3@example.org, regDate=2023-03-31T15:46:29.688Z]
Customer [id=4, name=CustName4, email=cust4@example.org, regDate=2023-03-31T15:46:30.688Z]
Customer [id=5, name=CustName5, email=cust5@example.org, regDate=2023-03-31T15:46:31.689Z]
MovieActor{movieName='movie01', actorName='actor0', actingAward='actingaward0', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

Output berikut menunjukkan item yang dikembalikan dan dicatat setelah baris komentar 4.

```
Customer [id=1, name=CustName1, email=cust1@example.org, regDate=2023-03-31T15:46:27.688Z]
Customer [id=2, name=CustName2, email=cust2@example.org, regDate=2023-03-31T15:46:28.688Z]
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
```

## Contoh `batchWriteItem()`
<a name="ddb-en-client-use-multiop-batch-write"></a>

`batchWriteItem()`Metode ini menempatkan atau menghapus beberapa item dalam satu atau lebih tabel. Anda dapat menentukan hingga 25 operasi put atau hapus individu dalam permintaan. Contoh berikut menggunakan kelas [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)dan [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)model yang ditunjukkan sebelumnya.

`WriteBatch`objek dibangun setelah baris komentar 1 dan 2. Untuk `ProductCatalog` tabel, kode menempatkan satu item dan menghapus satu item. Untuk `MovieActor` tabel setelah baris komentar 2, kode menempatkan dua item dan menghapus satu.

`batchWriteItem`Metode ini disebut setelah baris komentar 3. `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteItemEnhancedRequest.Builder.html)`Parameter menyediakan permintaan batch untuk setiap tabel.

`[BatchWriteResult](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteResult.html)`Objek yang dikembalikan menyediakan metode terpisah untuk setiap operasi untuk melihat permintaan yang belum diproses. Kode setelah baris komentar 4a menyediakan kunci untuk permintaan penghapusan yang belum diproses dan kode setelah baris komentar 4b menyediakan item put yang belum diproses.

```
    public static void batchWriteItemExample(DynamoDbEnhancedClient enhancedClient,
                                             DynamoDbTable<ProductCatalog> catalogTable,
                                             DynamoDbTable<MovieActor> movieActorTable) {

        // 1. Build a batch to write to the ProductCatalog table.
        WriteBatch products = WriteBatch.builder(ProductCatalog.class)
                .mappedTableResource(catalogTable)
                .addPutItem(b -> b.item(getProductCatItem1()))
                .addDeleteItem(b -> b.key(k -> k
                        .partitionValue(getProductCatItem2().id())
                        .sortValue(getProductCatItem2().title())))
                .build();

        // 2. Build a batch to write to the MovieActor table.
        WriteBatch movies = WriteBatch.builder(MovieActor.class)
                .mappedTableResource(movieActorTable)
                .addPutItem(getMovieActorYeoh())
                .addPutItem(getMovieActorBlanchettPartial())
                .addDeleteItem(b -> b.key(k -> k
                        .partitionValue(getMovieActorStreep().getMovieName())
                        .sortValue(getMovieActorStreep().getActorName())))
                .build();

        // 3. Add WriteBatch objects to the request.
        BatchWriteResult batchWriteResult = enhancedClient.batchWriteItem(b -> b.writeBatches(products, movies));
        // 4. Retrieve keys for items the service did not process.
        // 4a. 'unprocessedDeleteItemsForTable()' returns keys for delete requests that did not process.
        if (batchWriteResult.unprocessedDeleteItemsForTable(movieActorTable).size() > 0) {
            batchWriteResult.unprocessedDeleteItemsForTable(movieActorTable).forEach(key ->
                    logger.info(key.toString()));
        }
        // 4b. 'unprocessedPutItemsForTable()' returns keys for put requests that did not process.
        if (batchWriteResult.unprocessedPutItemsForTable(catalogTable).size() > 0) {
            batchWriteResult.unprocessedPutItemsForTable(catalogTable).forEach(key ->
                    logger.info(key.toString()));
        }
    }
```

Metode pembantu berikut menyediakan objek model untuk operasi put dan delete.

### Metode pembantu
<a name="ddb-en-client-use-multiop-batch-write-helpers"></a>

```
 1.     public static ProductCatalog getProductCatItem1() {
 2.         return ProductCatalog.builder()
 3.                 .id(2)
 4.                 .isbn("1-565-85698")
 5.                 .authors(new HashSet<>(Arrays.asList("a", "b")))
 6.                 .price(BigDecimal.valueOf(30.22))
 7.                 .title("Title 55")
 8.                 .build();
 9.     }
10. 
11.     public static ProductCatalog getProductCatItem2() {
12.         return ProductCatalog.builder()
13.                 .id(4)
14.                 .price(BigDecimal.valueOf(40.00))
15.                 .title("Title 1")
16.                 .build();
17.     }  
18. 
19.     public static MovieActor getMovieActorBlanchettPartial() {
20.         MovieActor movieActor = new MovieActor();
21.         movieActor.setActorName("Cate Blanchett");
22.         movieActor.setMovieName("Blue Jasmine");
23.         movieActor.setActingYear(2023);
24.         movieActor.setActingAward("Best Actress");
25.         return movieActor;
26.     }
27. 
28.     public static MovieActor getMovieActorStreep() {
29.         MovieActor movieActor = new MovieActor();
30.         movieActor.setActorName("Meryl Streep");
31.         movieActor.setMovieName("Sophie's Choice");
32.         movieActor.setActingYear(1982);
33.         movieActor.setActingAward("Best Actress");
34.         movieActor.setActingSchoolName("Yale School of Drama");
35.         return movieActor;
36.     }
37. 
38.     public static MovieActor getMovieActorYeoh(){
39.         MovieActor movieActor = new MovieActor();
40.         movieActor.setActorName("Michelle Yeoh");
41.         movieActor.setMovieName("Everything Everywhere All at Once");
42.         movieActor.setActingYear(2023);
43.         movieActor.setActingAward("Best Actress");
44.         movieActor.setActingSchoolName("Royal Academy of Dance");
45.         return movieActor;
46.     }
```

Asumsikan bahwa tabel berisi item berikut sebelum Anda menjalankan kode contoh.

```
MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
```

Setelah kode contoh selesai, tabel berisi item berikut.

```
MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='null'}
MovieActor{movieName='Everything Everywhere All at Once', actorName='Michelle Yeoh', actingAward='Best Actress', actingYear=2023, actingSchoolName='Royal Academy of Dance'}
ProductCatalog{id=2, title='Title 55', isbn='1-565-85698', authors=[a, b], price=30.22}
```

Perhatikan dalam `MovieActor` tabel bahwa item `Blue Jasmine` film telah diganti dengan item yang digunakan dalam permintaan put yang diperoleh melalui metode `getMovieActorBlanchettPartial()` pembantu. Jika nilai atribut kacang data tidak disediakan, nilai dalam database dihapus. Inilah sebabnya mengapa hasilnya `actingSchoolName` nol untuk item `Blue Jasmine` film.

**catatan**  
Meskipun dokumentasi API menunjukkan bahwa ekspresi kondisi dapat digunakan dan bahwa kapasitas yang dikonsumsi serta metrik pengumpulan dapat dikembalikan dengan permintaan [put](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PutItemEnhancedRequest.html) dan [delete](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.html) individual, ini tidak terjadi dalam skenario penulisan batch. Untuk meningkatkan kinerja operasi batch, opsi individual ini diabaikan.

# Lakukan operasi transaksi
<a name="ddb-en-client-use-multiop-trans"></a>

DynamoDB Enhanced Client API menyediakan dan metode`transactGetItems()`. `transactWriteItems()` Metode transaksi SDK for Java memberikan atomisitas, konsistensi, isolasi, dan daya tahan (ACID) dalam tabel DynamoDB, membantu Anda menjaga kebenaran data dalam aplikasi Anda.

## Contoh `transactGetItems()`
<a name="ddb-en-client-use-multiop-trans-getitems"></a>

`[transactGetItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactGetItems(java.util.function.Consumer))`Metode ini menerima hingga 100 permintaan individu untuk item. Semua item dibaca dalam satu transaksi atom. Panduan *Pengembang Amazon DynamoDB* memiliki informasi tentang [kondisi yang menyebabkan `transactGetItems()` metode gagal](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txgetitems), dan juga tentang tingkat isolasi yang digunakan saat Anda menelepon. `[transactGetItem()](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-isolation)`

Setelah baris komentar 1 dalam contoh berikut, kode memanggil `transactGetItems()` metode dengan `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html)` parameter. Builder `[addGetItem()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html#addGetItem(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource,T))` dipanggil tiga kali dengan objek data yang berisi nilai kunci yang akan digunakan SDK untuk menghasilkan permintaan akhir.

Permintaan mengembalikan daftar `[Document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html)` objek setelah baris komentar 2. Daftar dokumen yang dikembalikan berisi contoh [dokumen](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html) non-null dari data item dalam urutan yang sama seperti yang diminta. `[Document.getItem(MappedTableResource<T> mappedTableResource)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html#getItem(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))`Metode mengkonversi objek untyped menjadi `Document` objek Java diketik jika data item dikembalikan, jika tidak metode mengembalikan null.

```
    public static void transactGetItemsExample(DynamoDbEnhancedClient enhancedClient,
                                               DynamoDbTable<ProductCatalog> catalogTable,
                                               DynamoDbTable<MovieActor> movieActorTable) {

        // 1. Request three items from two tables using a builder.
        final List<Document> documents = enhancedClient.transactGetItems(b -> b
                .addGetItem(catalogTable, Key.builder().partitionValue(2).sortValue("Title 55").build())
                .addGetItem(movieActorTable, Key.builder().partitionValue("Sophie's Choice").sortValue("Meryl Streep").build())
                .addGetItem(movieActorTable, Key.builder().partitionValue("Blue Jasmine").sortValue("Cate Blanchett").build())
                .build());

        // 2. A list of Document objects is returned in the same order as requested.
        ProductCatalog title55 = documents.get(0).getItem(catalogTable);
        if (title55 != null) {
            logger.info(title55.toString());
        }

        MovieActor sophiesChoice = documents.get(1).getItem(movieActorTable);
        if (sophiesChoice != null) {
            logger.info(sophiesChoice.toString());
        }

        // 3. The getItem() method returns null if the Document object contains no item from DynamoDB.
        MovieActor blueJasmine = documents.get(2).getItem(movieActorTable);
        if (blueJasmine != null) {
            logger.info(blueJasmine.toString());
        }
    }
```

Tabel DynamoDB berisi item berikut sebelum contoh kode berjalan.

```
ProductCatalog{id=2, title='Title 55', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
```

Output berikut dicatat. Jika item diminta tetapi tidak ditemukan, itu tidak dikembalikan seperti halnya permintaan untuk film bernama`Blue Jasmine`.

```
ProductCatalog{id=2, title='Title 55', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
```

## `transactWriteItems()` contoh
<a name="ddb-en-client-use-multiop-trans-writeitems"></a>

`[transactWriteItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))`Menerima hingga 100 tindakan put, update, atau delete dalam satu transaksi atom di beberapa tabel. Panduan *Pengembang Amazon DynamoDB* berisi rincian tentang pembatasan dan kondisi kegagalan operasi layanan [DynamoDB yang mendasarinya](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems).

### Contoh basic
<a name="ddb-en-client-use-multiop-trans-writeitems-basic"></a>

Dalam contoh berikut, empat operasi diminta untuk dua tabel. Kelas model yang sesuai [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)dan ditunjukkan [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)sebelumnya.

Masing-masing dari tiga kemungkinan operasi—put, update, dan delete—menggunakan parameter permintaan khusus untuk menentukan detailnya. 

Kode setelah baris komentar 1 menunjukkan variasi sederhana dari `addPutItem()` metode ini. Metode ini menerima `[MappedTableResource](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/MappedTableResource.html)` objek dan contoh objek data untuk dimasukkan. Pernyataan setelah komentar baris 2 menunjukkan variasi yang menerima `[TransactPutItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactPutItemEnhancedRequest.html)` instance. Variasi ini memungkinkan Anda menambahkan lebih banyak opsi dalam permintaan, seperti ekspresi kondisi. [Contoh](#ddb-en-client-use-multiop-trans-writeitems-opcondition) selanjutnya menunjukkan ekspresi kondisi untuk operasi individu.

Operasi pembaruan diminta setelah baris komentar 3. `[TransactUpdateItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactUpdateItemEnhancedRequest.Builder.html)`memiliki `ignoreNulls()` metode yang memungkinkan Anda mengonfigurasi apa yang dilakukan SDK dengan `null` nilai pada objek model. Jika `ignoreNulls()` metode mengembalikan true, SDK tidak menghapus nilai atribut tabel untuk atribut objek data yang`null`. Jika `ignoreNulls()` metode mengembalikan false, SDK meminta layanan DynamoDB untuk menghapus atribut dari item dalam tabel. Nilai default untuk `ignoreNulls` adalah false.

Pernyataan setelah baris komentar 4 menunjukkan variasi permintaan hapus yang mengambil objek data. Klien yang disempurnakan mengekstrak nilai-nilai kunci sebelum mengirimkan permintaan akhir.

```
    public static void transactWriteItems(DynamoDbEnhancedClient enhancedClient,
                                          DynamoDbTable<ProductCatalog> catalogTable,
                                          DynamoDbTable<MovieActor> movieActorTable) {

        enhancedClient.transactWriteItems(b -> b
                // 1. Simplest variation of put item request.
                .addPutItem(catalogTable, getProductCatId2())
                // 2. Put item request variation that accommodates condition expressions.
                .addPutItem(movieActorTable, TransactPutItemEnhancedRequest.builder(MovieActor.class)
                        .item(getMovieActorStreep())
                        .conditionExpression(Expression.builder().expression("attribute_not_exists (movie)").build())
                        .build())
                // 3. Update request that does not remove attribute values on the table if the data object's value is null.
                .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class)
                        .item(getProductCatId4ForUpdate())
                        .ignoreNulls(Boolean.TRUE)
                        .build())
                // 4. Variation of delete request that accepts a data object. The key values are extracted for the request.
                .addDeleteItem(movieActorTable, getMovieActorBlanchett())
        );
    }
```

Metode pembantu berikut menyediakan objek data untuk `add*Item` parameter.

#### Metode pembantu
<a name="ddb-en-client-use-multiop-trans-writeitems-basic-helpers"></a>

```
    public static ProductCatalog getProductCatId2() {
        return ProductCatalog.builder()
                .id(2)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(30.22))
                .title("Title 55")
                .build();
    }

    public static ProductCatalog getProductCatId4ForUpdate() {
        return ProductCatalog.builder()
                .id(4)
                .price(BigDecimal.valueOf(40.00))
                .title("Title 1")
                .build();
    }

    public static MovieActor getMovieActorBlanchett() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Cate Blanchett");
        movieActor.setMovieName("Tar");
        movieActor.setActingYear(2022);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("National Institute of Dramatic Art");
        return movieActor;
    }

    public static MovieActor getMovieActorStreep() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Meryl Streep");
        movieActor.setMovieName("Sophie's Choice");
        movieActor.setActingYear(1982);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("Yale School of Drama");
        return movieActor;
    }
```

Tabel DynamoDB berisi item berikut sebelum contoh kode berjalan.

```
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
```

Item berikut ada di tabel setelah kode selesai berjalan.

```
3 | ProductCatalog{id=2, title='Title 55', isbn='1-565-85698', authors=[a, b], price=30.22}
4 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=40.0}
5 | MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
```

Item pada baris 2 telah dihapus dan baris 3 dan 5 menunjukkan item yang diletakkan. Baris 4 menunjukkan pembaruan baris 1. `price`Nilai adalah satu-satunya nilai yang berubah pada item. Jika `ignoreNulls()` telah mengembalikan false, baris 4 akan terlihat seperti baris berikut.

```
ProductCatalog{id=4, title='Title 1', isbn='null', authors=null, price=40.0}
```

### Contoh pemeriksaan kondisi
<a name="ddb-en-client-use-multiop-trans-writeitems-checkcond"></a>

Contoh berikut menunjukkan penggunaan pemeriksaan kondisi. Pemeriksaan kondisi digunakan untuk memeriksa apakah ada item atau untuk memeriksa kondisi atribut tertentu dari suatu item dalam database. Item yang dicek dalam pemeriksaan kondisi tidak dapat digunakan dalam operasi lain dalam transaksi.

**catatan**  
Anda tidak dapat menargetkan item yang sama dengan beberapa operasi dalam transaksi yang sama. Misalnya, Anda tidak dapat melakukan pemeriksaan kondisi dan juga mencoba memperbarui item yang sama dalam transaksi yang sama.

Contoh menunjukkan salah satu dari setiap jenis operasi dalam permintaan item tulis transaksional. Setelah baris komentar 2, `addConditionCheck()` metode memasok kondisi yang gagal transaksi jika `conditionExpression` parameter mengevaluasi`false`. Ekspresi kondisi yang dikembalikan dari metode yang ditampilkan dalam blok Metode Pembantu memeriksa apakah tahun penghargaan untuk film `Sophie's Choice` tidak sama dengan. `1982` Jika ya, ekspresi mengevaluasi `false` dan transaksi gagal.

Panduan ini membahas [ekspresi](ddb-en-client-expressions.md) secara mendalam dalam topik lain.

```
    public static void conditionCheckFailExample(DynamoDbEnhancedClient enhancedClient,
                                                 DynamoDbTable<ProductCatalog> catalogTable,
                                                 DynamoDbTable<MovieActor> movieActorTable) {

        try {
            enhancedClient.transactWriteItems(b -> b
                    // 1. Perform one of each type of operation with the next three methods.
                    .addPutItem(catalogTable, TransactPutItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId2()).build())
                    .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId4ForUpdate())
                            .ignoreNulls(Boolean.TRUE).build())
                    .addDeleteItem(movieActorTable, TransactDeleteItemEnhancedRequest.builder()
                            .key(b1 -> b1
                                    .partitionValue(getMovieActorBlanchett().getMovieName())
                                    .sortValue(getMovieActorBlanchett().getActorName())).build())
                    // 2. Add a condition check on a table item that is not involved in another operation in this request.
                    .addConditionCheck(movieActorTable, ConditionCheck.builder()
                            .conditionExpression(buildConditionCheckExpression())
                            .key(k -> k
                                    .partitionValue("Sophie's Choice")
                                    .sortValue("Meryl Streep"))
                            // 3. Specify the request to return existing values from the item if the condition evaluates to true.
                            .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
                            .build())
                    .build());
        // 4. Catch the exception if the transaction fails and log the information.
        } catch (TransactionCanceledException ex) {
            ex.cancellationReasons().stream().forEach(cancellationReason -> {
                logger.info(cancellationReason.toString());
            });
        }
    }
```

Metode pembantu berikut digunakan dalam contoh kode sebelumnya.

#### Metode pembantu
<a name="ddb-en-client-use-multiop-trans-writeitems-checkcond-helpers"></a>

```
    private static Expression buildConditionCheckExpression() {
        Map<String, AttributeValue> expressionValue = Map.of(
                ":year", numberValue(1982));

        return Expression.builder()
                .expression("actingyear <> :year")
                .expressionValues(expressionValue)
                .build();
    }

    public static ProductCatalog getProductCatId2() {
        return ProductCatalog.builder()
                .id(2)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(30.22))
                .title("Title 55")
                .build();
    }

    public static ProductCatalog getProductCatId4ForUpdate() {
        return ProductCatalog.builder()
                .id(4)
                .price(BigDecimal.valueOf(40.00))
                .title("Title 1")
                .build();
    }

    public static MovieActor getMovieActorBlanchett() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Cate Blanchett");
        movieActor.setMovieName("Blue Jasmine");
        movieActor.setActingYear(2013);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("National Institute of Dramatic Art");
        return movieActor;
    }
```

Tabel DynamoDB berisi item berikut sebelum contoh kode berjalan.

```
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
3 | MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
```

Item berikut ada di tabel setelah kode selesai berjalan.

```
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
```

Item tetap tidak berubah dalam tabel karena transaksi gagal. `actingYear`Nilai untuk film `Sophie's Choice` adalah`1982`, seperti yang ditunjukkan pada baris 2 item dalam tabel sebelum `transactWriteItem()` metode dipanggil.

Untuk menangkap informasi pembatalan untuk transaksi, lampirkan panggilan `transactWriteItems()` metode dalam `try` blok dan`catch`. [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/TransactionCanceledException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/TransactionCanceledException.html) Setelah baris komentar 4 dari contoh, kode mencatat setiap `[CancellationReason](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CancellationReason.html)` objek. Karena kode berikut baris komentar 3 dari contoh menentukan bahwa nilai harus dikembalikan untuk item yang menyebabkan transaksi gagal, log menampilkan nilai database mentah untuk item `Sophie's Choice` film.

```
CancellationReason(Code=None)
CancellationReason(Code=None)
CancellationReason(Code=None)
CancellationReason(Item={actor=AttributeValue(S=Meryl Streep), movie=AttributeValue(S=Sophie's Choice), actingaward=AttributeValue(S=Best Actress), actingyear=AttributeValue(N=1982), actingschoolname=AttributeValue(S=Yale School of Drama)}, ¬
    Code=ConditionalCheckFailed, Message=The conditional request failed.)
```

### Contoh kondisi operasi tunggal
<a name="ddb-en-client-use-multiop-trans-writeitems-opcondition"></a>

Contoh berikut menunjukkan penggunaan kondisi pada operasi tunggal dalam permintaan transaksi. Operasi hapus setelah baris komentar 1 berisi kondisi yang memeriksa nilai item target operasi terhadap database. Dalam contoh ini, ekspresi kondisi yang dibuat dengan metode pembantu setelah baris komentar 2 menentukan bahwa item harus dihapus dari database jika tahun akting film tidak sama dengan 2013.

[Ekspresi](ddb-en-client-expressions.md) dibahas nanti dalam panduan ini.

```
    public static void singleOperationConditionFailExample(DynamoDbEnhancedClient enhancedClient,
                                                           DynamoDbTable<ProductCatalog> catalogTable,
                                                           DynamoDbTable<MovieActor> movieActorTable) {
        try {
            enhancedClient.transactWriteItems(b -> b
                    .addPutItem(catalogTable, TransactPutItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId2())
                            .build())
                    .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId4ForUpdate())
                            .ignoreNulls(Boolean.TRUE).build())
                    // 1. Delete operation that contains a condition expression
                    .addDeleteItem(movieActorTable, TransactDeleteItemEnhancedRequest.builder()
                            .key((Key.Builder k) -> {
                                MovieActor blanchett = getMovieActorBlanchett();
                                k.partitionValue(blanchett.getMovieName())
                                        .sortValue(blanchett.getActorName());
                            })
                            .conditionExpression(buildDeleteItemExpression())
                            .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
                            .build())
                    .build());
        } catch (TransactionCanceledException ex) {
            ex.cancellationReasons().forEach(cancellationReason -> logger.info(cancellationReason.toString()));
        }
    }

    // 2. Provide condition expression to check if 'actingyear' is not equal to 2013.
    private static Expression buildDeleteItemExpression() {
        Map<String, AttributeValue> expressionValue = Map.of(
                ":year", numberValue(2013));

        return Expression.builder()
                .expression("actingyear <> :year")
                .expressionValues(expressionValue)
                .build();
    }
```

Metode pembantu berikut digunakan dalam contoh kode sebelumnya.

#### Metode pembantu
<a name="ddb-en-client-use-multiop-trans-writeitems-opcondition-helpers"></a>

```
    public static ProductCatalog getProductCatId2() {
        return ProductCatalog.builder()
                .id(2)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(30.22))
                .title("Title 55")
                .build();
    }

    public static ProductCatalog getProductCatId4ForUpdate() {
        return ProductCatalog.builder()
                .id(4)
                .price(BigDecimal.valueOf(40.00))
                .title("Title 1")
                .build();
    }
    public static MovieActor getMovieActorBlanchett() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Cate Blanchett");
        movieActor.setMovieName("Blue Jasmine");
        movieActor.setActingYear(2013);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("National Institute of Dramatic Art");
        return movieActor;
    }
```

Tabel DynamoDB berisi item berikut sebelum contoh kode berjalan.

```
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
```

Item berikut ada di tabel setelah kode selesai berjalan.

```
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2023-03-15 11:29:07 [main] INFO  org.example.tests.TransactDemoTest:168 - MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
```

Item tetap tidak berubah dalam tabel karena transaksi gagal. `actingYear`Nilai untuk film `Blue Jasmine` adalah `2013` seperti yang ditunjukkan pada baris 2 dalam daftar item sebelum contoh kode berjalan.

Baris berikut dicatat ke konsol.

```
CancellationReason(Code=None)
CancellationReason(Code=None)
CancellationReason(Item={actor=AttributeValue(S=Cate Blanchett), movie=AttributeValue(S=Blue Jasmine), actingaward=AttributeValue(S=Best Actress), actingyear=AttributeValue(N=2013), actingschoolname=AttributeValue(S=National Institute of Dramatic Art)}, 
    Code=ConditionalCheckFailed, Message=The conditional request failed)
```

# Gunakan indeks sekunder
<a name="ddb-en-client-use-secindex"></a>

Indeks sekunder meningkatkan akses data dengan mendefinisikan kunci alternatif yang Anda gunakan dalam operasi kueri dan pemindaian. Indeks sekunder global (GSI) memiliki kunci partisi dan kunci pengurutan yang dapat berbeda dari yang ada di tabel dasar. Sebaliknya, indeks sekunder lokal (LSI) menggunakan kunci partisi dari indeks primer.

## Anotasi kelas data dengan anotasi indeks sekunder
<a name="ddb-en-client-use-secindex-annomodel"></a>

Atribut yang berpartisipasi dalam indeks sekunder memerlukan `@DynamoDbSecondarySortKey` anotasi `@DynamoDbSecondaryPartitionKey` atau anotasi.

Kelas berikut menunjukkan anotasi untuk dua indeks. GSI bernama *SubjectLastPostedDateIndex*menggunakan `Subject` atribut untuk kunci partisi dan `LastPostedDateTime` untuk kunci sortir. LSI bernama *ForumLastPostedDateIndex*menggunakan `ForumName` sebagai kunci partisi dan `LastPostedDateTime` sebagai kunci sortir.

Perhatikan bahwa `Subject` atribut tersebut memiliki peran ganda. Ini adalah kunci sortir kunci primer dan kunci partisi dari GSI bernama *SubjectLastPostedDateIndex*.

### `MessageThread` kelas
<a name="ddb-en-client-use-secindex-class"></a>

`MessageThread`Kelas ini cocok untuk digunakan sebagai kelas data untuk [tabel Thread contoh](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AppendixSampleTables.html) di *Amazon DynamoDB* Developer Guide.

#### Impor
<a name="ddb-en-client-use-secindex-classimports"></a>

```
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
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.util.List;
```

```
@DynamoDbBean
public class MessageThread {
    private String ForumName;
    private String Subject;
    private String Message;
    private String LastPostedBy;
    private String LastPostedDateTime;
    private Integer Views;
    private Integer Replies;
    private Integer Answered;
    private List<String> Tags;

    @DynamoDbPartitionKey
    public String getForumName() {
        return ForumName;
    }

    public void setForumName(String forumName) {
        ForumName = forumName;
    }

    // Sort key for primary index and partition key for GSI "SubjectLastPostedDateIndex".
    @DynamoDbSortKey
    @DynamoDbSecondaryPartitionKey(indexNames = "SubjectLastPostedDateIndex")
    public String getSubject() {
        return Subject;
    }

    public void setSubject(String subject) {
        Subject = subject;
    }

    // Sort key for GSI "SubjectLastPostedDateIndex" and sort key for LSI "ForumLastPostedDateIndex".
    @DynamoDbSecondarySortKey(indexNames = {"SubjectLastPostedDateIndex", "ForumLastPostedDateIndex"})
    public String getLastPostedDateTime() {
        return LastPostedDateTime;
    }

    public void setLastPostedDateTime(String lastPostedDateTime) {
        LastPostedDateTime = lastPostedDateTime;
    }
    public String getMessage() {
        return Message;
    }

    public void setMessage(String message) {
        Message = message;
    }

    public String getLastPostedBy() {
        return LastPostedBy;
    }

    public void setLastPostedBy(String lastPostedBy) {
        LastPostedBy = lastPostedBy;
    }

    public Integer getViews() {
        return Views;
    }

    public void setViews(Integer views) {
        Views = views;
    }

    @DynamoDbSecondaryPartitionKey(indexNames = "ForumRepliesIndex")
    public Integer getReplies() {
        return Replies;
    }

    public void setReplies(Integer replies) {
        Replies = replies;
    }

    public Integer getAnswered() {
        return Answered;
    }

    public void setAnswered(Integer answered) {
        Answered = answered;
    }

    public List<String> getTags() {
        return Tags;
    }

    public void setTags(List<String> tags) {
        Tags = tags;
    }

    public MessageThread() {
        this.Answered = 0;
        this.LastPostedBy = "";
        this.ForumName = "";
        this.Message = "";
        this.LastPostedDateTime = "";
        this.Replies = 0;
        this.Views = 0;
        this.Subject = "";
    }

    @Override
    public String toString() {
        return "MessageThread{" +
                "ForumName='" + ForumName + '\'' +
                ", Subject='" + Subject + '\'' +
                ", Message='" + Message + '\'' +
                ", LastPostedBy='" + LastPostedBy + '\'' +
                ", LastPostedDateTime='" + LastPostedDateTime + '\'' +
                ", Views=" + Views +
                ", Replies=" + Replies +
                ", Answered=" + Answered +
                ", Tags=" + Tags +
                '}';
    }
}
```

## Buat indeks
<a name="ddb-en-client-use-secindex-confindex"></a>

Dimulai dengan versi 2.20.86 SDK for Java, `createTable()` metode ini secara otomatis menghasilkan indeks sekunder dari anotasi kelas data. Secara default, semua atribut dari tabel dasar disalin ke indeks dan nilai throughput yang disediakan adalah 20 unit kapasitas baca dan 20 unit kapasitas tulis.

Namun, jika Anda menggunakan versi SDK sebelum 2.20.86, Anda perlu membuat indeks bersama dengan tabel seperti yang ditunjukkan pada contoh berikut. Contoh ini membangun dua indeks untuk tabel. `Thread` Parameter [builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html) memiliki metode untuk mengkonfigurasi kedua jenis indeks seperti yang ditunjukkan setelah baris komentar 1 dan 2. Anda menggunakan `indexName()` metode pembuat indeks untuk mengaitkan nama indeks yang ditentukan dalam anotasi kelas data dengan jenis indeks yang dimaksud.

Kode ini mengkonfigurasi semua atribut tabel untuk berakhir di kedua indeks setelah baris komentar 3 dan 4. Informasi selengkapnya tentang [proyeksi atribut](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html#LSI.Projections) tersedia di Panduan Pengembang *Amazon DynamoDB*.

```
    public static void createMessageThreadTable(DynamoDbTable<MessageThread> messageThreadDynamoDbTable, DynamoDbClient dynamoDbClient) {
        messageThreadDynamoDbTable.createTable(b -> b
                // 1. Generate the GSI.
                .globalSecondaryIndices(gsi -> gsi.indexName("SubjectLastPostedDateIndex")
                        // 3. Populate the GSI with all attributes.
                        .projection(p -> p
                                .projectionType(ProjectionType.ALL))
                )
                // 2. Generate the LSI.
                .localSecondaryIndices(lsi -> lsi.indexName("ForumLastPostedDateIndex")
                        // 4. Populate the LSI with all attributes.
                        .projection(p -> p
                                .projectionType(ProjectionType.ALL))
                )
        );
```

## Kueri dengan menggunakan indeks
<a name="ddb-en-client-use-secindex-query"></a>

Contoh berikut query indeks *ForumLastPostedDateIndex*sekunder lokal.

Mengikuti baris komentar 2, Anda membuat [QueryConditional](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html)objek yang diperlukan saat memanggil [DynamoDbIndexmetode.query ()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbIndex.html#query(java.util.function.Consumer)). 

Anda mendapatkan referensi ke indeks yang ingin Anda kueri setelah baris komentar 3 dengan meneruskan nama indeks. Mengikuti baris komentar 4, Anda memanggil `query()` metode pada indeks yang lewat di `QueryConditional` objek. 

Anda juga mengonfigurasi kueri untuk mengembalikan tiga nilai atribut seperti yang ditunjukkan setelah baris komentar 5. Jika tidak `attributesToProject()` dipanggil, query mengembalikan semua nilai atribut. Perhatikan bahwa nama atribut yang ditentukan dimulai dengan huruf kecil. Nama atribut ini cocok dengan yang digunakan dalam tabel, belum tentu nama atribut dari kelas data.

Mengikuti baris komentar 6, ulangi hasil dan log setiap item yang dikembalikan oleh kueri dan juga menyimpannya dalam daftar untuk kembali ke pemanggil.

```
public class IndexScanExamples {
    private static Logger logger = LoggerFactory.getLogger(IndexScanExamples.class);

    public static List<MessageThread> queryUsingSecondaryIndices(String lastPostedDate,
                                                                 DynamoDbTable<MessageThread> threadTable) {
        // 1. Log the parameter value.
        logger.info("lastPostedDate value: {}", lastPostedDate);

        // 2. Create a QueryConditional whose sort key value must be greater than or equal to the parameter value.
        QueryConditional queryConditional = QueryConditional.sortGreaterThanOrEqualTo(qc ->
                qc.partitionValue("Forum02").sortValue(lastPostedDate));

        // 3. Specify the index name to query.
        final DynamoDbIndex<MessageThread> forumLastPostedDateIndex = threadTable.index("ForumLastPostedDateIndex");

        // 4. Perform the query using the QueryConditional object.
        final SdkIterable<Page<MessageThread>> pagedResult = forumLastPostedDateIndex.query(q -> q
                .queryConditional(queryConditional)
                // 5. Request three attribute in the results.
                .attributesToProject("forumName", "subject", "lastPostedDateTime"));

        List<MessageThread> collectedItems = new ArrayList<>();
        // 6. Iterate through pages response and sort the items.
        pagedResult.stream().forEach(page -> page.items().stream()
                .sorted(Comparator.comparing(MessageThread::getLastPostedDateTime))
                .forEach(mt -> {
                    // 7. Log the returned items and add the collection to return to the caller.
                    logger.info(mt.toString());
                    collectedItems.add(mt);
                }));
        return collectedItems;
    }
```

Item berikut ada dalam database sebelum query dijalankan.

```
MessageThread{ForumName='Forum01', Subject='Subject01', Message='Message01', LastPostedBy='', LastPostedDateTime='2023.03.28', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject02', Message='Message02', LastPostedBy='', LastPostedDateTime='2023.03.29', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject04', Message='Message04', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject08', Message='Message08', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject10', Message='Message10', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject03', Message='Message03', LastPostedBy='', LastPostedDateTime='2023.03.30', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject06', Message='Message06', LastPostedBy='', LastPostedDateTime='2023.04.02', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject09', Message='Message09', LastPostedBy='', LastPostedDateTime='2023.04.05', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum05', Subject='Subject05', Message='Message05', LastPostedBy='', LastPostedDateTime='2023.04.01', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum07', Subject='Subject07', Message='Message07', LastPostedBy='', LastPostedDateTime='2023.04.03', Views=0, Replies=0, Answered=0, Tags=null}
```

Pernyataan logging pada baris 1 dan 6 menghasilkan output konsol berikut.

```
lastPostedDate value: 2023.03.31
MessageThread{ForumName='Forum02', Subject='Subject04', Message='', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject08', Message='', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject10', Message='', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null}
```

*Kueri mengembalikan item dengan `forumName` nilai *Forum02* dan `lastPostedDateTime` nilai lebih besar dari atau sama dengan 2023.03.31.* Hasilnya menunjukkan `message` nilai dengan string kosong meskipun `message` atribut memiliki nilai dalam indeks. Ini karena atribut pesan tidak diproyeksikan oleh kode setelah baris komentar 5. 

# Gunakan fitur pemetaan tingkat lanjut
<a name="ddb-en-client-adv-features"></a>

Pelajari tentang fitur skema tabel lanjutan di DynamoDB Enhanced Client API.

## Memahami jenis skema tabel
<a name="ddb-en-client-adv-features-schm-overview"></a>

`[TableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableSchema.html)`adalah antarmuka ke fungsionalitas pemetaan DynamoDB Enhanced Client API. Hal ini dapat memetakan objek data ke dan dari peta [AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html). Sebuah `TableSchema` objek perlu tahu tentang struktur tabel yang dipetakannya. Informasi struktur ini disimpan dalam suatu [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableMetadata.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableMetadata.html)objek.

API klien yang disempurnakan memiliki beberapa implementasi`TableSchema`, yang mengikuti. 

### Skema tabel yang dihasilkan dari kelas beranotasi
<a name="ddb-en-client-adv-features-schema-mapped"></a>

Ini adalah operasi yang cukup mahal untuk membangun `TableSchema` dari kelas beranotasi, jadi kami sarankan melakukan ini sekali, saat startup aplikasi.

 [ BeanTableSchema ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/BeanTableSchema.html)   
Implementasi ini dibangun berdasarkan atribut dan anotasi kelas kacang. Contoh pendekatan ini ditunjukkan di [bagian Memulai](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean).  
Jika a `BeanTableSchema` tidak berperilaku seperti yang Anda harapkan, aktifkan pencatatan debug untuk. `software.amazon.awssdk.enhanced.dynamodb.beans`

[ImmutableTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/ImmutableTableSchema.html)  
Implementasi ini dibangun dari kelas data yang tidak dapat diubah. Pendekatan ini dijelaskan di [Bekerja dengan kelas data yang tidak dapat diubah](ddb-en-client-use-immut.md) bagian ini.

### Skema tabel yang dihasilkan dengan pembangun
<a name="ddb-en-client-adv-features-schema-static"></a>

Berikut `TableSchema` s dibangun dari kode dengan menggunakan pembangun. Pendekatan ini lebih murah daripada pendekatan yang menggunakan kelas data beranotasi. Pendekatan builder menghindari penggunaan anotasi dan tidak memerlukan standar JavaBean penamaan.

[StaticTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticTableSchema.html)  
Implementasi ini dibangun untuk kelas data yang bisa berubah. Bagian memulai dari panduan ini menunjukkan cara [membuat `StaticTableSchema` menggunakan pembangun](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-builder).

[StaticImmutableTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticImmutableTableSchema.html)  
Demikian pula dengan cara Anda membangun`StaticTableSchema`, Anda menghasilkan implementasi jenis ini `TableSchema` menggunakan [pembangun](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticImmutableTableSchema.html) untuk digunakan dengan kelas data yang tidak dapat diubah.

### Skema tabel untuk data tanpa skema tetap
<a name="ddb-en-client-adv-features-schema-document"></a>

[DocumentTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/DocumentTableSchema.html)  
Tidak seperti implementasi lain dari`TableSchema`, Anda tidak mendefinisikan atribut untuk sebuah `DocumentTableSchema` instance. Biasanya, Anda hanya menentukan kunci utama dan penyedia konverter atribut. Sebuah `EnhancedDocument` instance menyediakan atribut yang Anda bangun dari elemen individual atau dari string JSON.

# Sertakan atau kecualikan atribut secara eksplisit
<a name="ddb-en-client-adv-features-inex-attr"></a>

DynamoDB Enhanced Client API menawarkan anotasi untuk mengecualikan atribut kelas data agar tidak menjadi atribut pada tabel. Dengan API, Anda juga dapat menggunakan nama atribut yang berbeda dari nama atribut kelas data.

## Kecualikan atribut
<a name="ddb-en-client-adv-features-inex-attr-ex"></a>

Untuk mengabaikan atribut yang seharusnya tidak dipetakan ke tabel DynamoDB, tandai atribut dengan anotasi. `@DynamoDbIgnore`

```
private String internalKey;

@DynamoDbIgnore
public String getInternalKey() { return this.internalKey; }
public void setInternalKey(String internalKey) { this.internalKey = internalKey;}
```

## Sertakan atribut
<a name="ddb-en-client-adv-features-inex-attr-in"></a>

Untuk mengubah nama atribut yang digunakan dalam tabel DynamoDB, tandai dengan anotasi dan berikan nama `@DynamoDbAttribute` yang berbeda.

```
private String internalKey;

@DynamoDbAttribute("renamedInternalKey")
public String getInternalKey() { return this.internalKey; }
public void setInternalKey(String internalKey) { this.internalKey = internalKey;}
```

# Konversi atribut kontrol
<a name="ddb-en-client-adv-features-conversion"></a>

Secara default, skema tabel menyediakan konverter untuk banyak jenis Java umum melalui implementasi default antarmuka. `[AttributeConverterProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverterProvider.html)` Anda dapat mengubah keseluruhan perilaku default dengan `AttributeConverterProvider` implementasi kustom. Anda juga dapat mengubah konverter untuk satu atribut.

Untuk daftar konverter yang tersedia, lihat [AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html)antarmuka Java doc.

## Menyediakan penyedia konverter atribut khusus
<a name="ddb-en-client-adv-features-conversion-prov"></a>

Anda dapat memberikan satu `AttributeConverterProvider` atau satu rantai `AttributeConverterProvider` s yang dipesan melalui `@DynamoDbBean` `(converterProviders = {…})` anotasi. Setiap kustom `AttributeConverterProvider` harus memperluas `AttributeConverterProvider` antarmuka.

Perhatikan bahwa jika Anda menyediakan rantai penyedia konverter atribut Anda sendiri, Anda akan mengganti penyedia konverter default,`DefaultAttributeConverterProvider`. Jika Anda ingin menggunakan fungsionalitas`DefaultAttributeConverterProvider`, Anda harus memasukkannya ke dalam rantai. 

Dimungkinkan juga untuk membubuhi keterangan kacang dengan array kosong. `{}` Ini menonaktifkan penggunaan penyedia konverter atribut apa pun, termasuk default. Dalam hal ini semua atribut yang akan dipetakan harus memiliki konverter atribut mereka sendiri.

Cuplikan berikut menunjukkan penyedia konverter tunggal.

```
@DynamoDbBean(converterProviders = ConverterProvider1.class)
public class Customer {

}
```

Cuplikan berikut menunjukkan penggunaan rantai penyedia konverter. Karena default SDK disediakan terakhir, ia memiliki prioritas terendah.

```
@DynamoDbBean(converterProviders = {
   ConverterProvider1.class, 
   ConverterProvider2.class,
   DefaultAttributeConverterProvider.class})
public class Customer {

}
```

Pembangun skema tabel statis memiliki `attributeConverterProviders()` metode yang bekerja dengan cara yang sama. Ini ditunjukkan dalam cuplikan berikut.

```
private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
  StaticTableSchema.builder(Customer.class)
    .newItemSupplier(Customer::new)
    .addAttribute(String.class, a -> a.name("name")
                                     a.getter(Customer::getName)
                                     a.setter(Customer::setName))
    .attributeConverterProviders(converterProvider1, converterProvider2)
    .build();
```

## Ganti pemetaan atribut tunggal
<a name="ddb-en-client-adv-features-conversion-single"></a>

Untuk mengganti cara atribut tunggal dipetakan, berikan atribut `AttributeConverter` untuk atribut. Penambahan ini mengesampingkan konverter apa pun yang disediakan oleh skema `AttributeConverterProviders` tabel. Ini menambahkan konverter khusus hanya untuk atribut itu. Atribut lain, bahkan yang dari tipe yang sama, tidak akan menggunakan konverter itu kecuali jika secara eksplisit ditentukan untuk atribut lainnya.

`@DynamoDbConvertedBy`Anotasi ini digunakan untuk menentukan `AttributeConverter` kelas kustom seperti yang ditunjukkan dalam cuplikan berikut.

```
@DynamoDbBean
public class Customer {
    private String name;

    @DynamoDbConvertedBy(CustomAttributeConverter.class)
    public String getName() { return this.name; }
    public void setName(String name) { this.name = name;}
}
```

Pembangun untuk skema statis memiliki `attributeConverter()` metode pembangun atribut yang setara. Metode ini mengambil contoh dari `AttributeConverter` sebagai berikut menunjukkan.

```
private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
  StaticTableSchema.builder(Customer.class)
    .newItemSupplier(Customer::new)
    .addAttribute(String.class, a -> a.name("name")
                                     a.getter(Customer::getName)
                                     a.setter(Customer::setName)
                                     a.attributeConverter(customAttributeConverter))
    .build();
```

## Contoh
<a name="ddb-en-client-adv-features-conversion-example"></a>

Contoh ini menunjukkan `AttributeConverterProvider` implementasi yang menyediakan konverter atribut untuk [https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpCookie.html](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpCookie.html)objek. 

`SimpleUser`Kelas berikut berisi atribut bernama `lastUsedCookie` yang merupakan instance dari`HttpCookie`.

Parameter untuk `@DynamoDbBean` anotasi mencantumkan dua `AttributeConverterProvider` kelas yang menyediakan konverter.

------
#### [ Class with annotations ]

```
    @DynamoDbBean(converterProviders = {CookieConverterProvider.class, DefaultAttributeConverterProvider.class})
    public static final class SimpleUser {
        private String name;
        private HttpCookie lastUsedCookie;

        @DynamoDbPartitionKey
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public HttpCookie getLastUsedCookie() {
            return lastUsedCookie;
        }

        public void setLastUsedCookie(HttpCookie lastUsedCookie) {
            this.lastUsedCookie = lastUsedCookie;
        }
```

------
#### [ Static table schema ]

```
    private static final TableSchema<SimpleUser> SIMPLE_USER_TABLE_SCHEMA =
            TableSchema.builder(SimpleUser.class)
                    .newItemSupplier(SimpleUser::new)
                    .attributeConverterProviders(CookieConverterProvider.create(), AttributeConverterProvider.defaultProvider())
                    .addAttribute(String.class, a -> a.name("name")
                            .setter(SimpleUser::setName)
                            .getter(SimpleUser::getName)
                            .tags(StaticAttributeTags.primaryPartitionKey()))
                    .addAttribute(HttpCookie.class, a -> a.name("lastUsedCookie")
                            .setter(SimpleUser::setLastUsedCookie)
                            .getter(SimpleUser::getLastUsedCookie))
                    .build();
```

------

`CookieConverterProvider`Dalam contoh berikut memberikan contoh dari sebuah`HttpCookeConverter`.

```
    public static final class CookieConverterProvider implements AttributeConverterProvider {
        private final Map<EnhancedType<?>, AttributeConverter<?>> converterCache = ImmutableMap.of(
                // 1. Add HttpCookieConverter to the internal cache.
                EnhancedType.of(HttpCookie.class), new HttpCookieConverter());

        public static CookieConverterProvider create() {
            return new CookieConverterProvider();
        }

        // The SDK calls this method to find out if the provider contains a AttributeConverter instance
        // for the EnhancedType<T> argument.
        @SuppressWarnings("unchecked")
        @Override
        public <T> AttributeConverter<T> converterFor(EnhancedType<T> enhancedType) {
            return (AttributeConverter<T>) converterCache.get(enhancedType);
        }
    }
```

### Kode konversi
<a name="ddb-en-client-adv-features-conversion-example-code"></a>

Dalam `transformFrom()` metode `HttpCookieConverter` kelas berikut, kode menerima `HttpCookie` instance dan mengubahnya menjadi peta DynamoDB yang disimpan sebagai atribut.

`transformTo()`Metode menerima parameter peta DynamoDB, kemudian memanggil konstruktor `HttpCookie` yang membutuhkan nama dan nilai.

```
    public static final class HttpCookieConverter implements AttributeConverter<HttpCookie> {

        @Override
        public AttributeValue transformFrom(HttpCookie httpCookie) {

            return AttributeValue.fromM(
            Map.of ("cookieName", AttributeValue.fromS(httpCookie.getName()),
                    "cookieValue", AttributeValue.fromS(httpCookie.getValue()))
            );
        }

        @Override
        public HttpCookie transformTo(AttributeValue attributeValue) {
            Map<String, AttributeValue> map = attributeValue.m();
            return new HttpCookie(
                    map.get("cookieName").s(),
                    map.get("cookieValue").s());
        }

        @Override
        public EnhancedType<HttpCookie> type() {
            return EnhancedType.of(HttpCookie.class);
        }

        @Override
        public AttributeValueType attributeValueType() {
            return AttributeValueType.M;
        }
    }
```

# Ubah perilaku pembaruan atribut
<a name="ddb-en-client-adv-features-upd-behavior"></a>

Anda dapat menyesuaikan perilaku pembaruan atribut individual saat Anda melakukan operasi *pembaruan*. [Beberapa contoh operasi pembaruan di DynamoDB Enhanced Client API [adalah updateItem](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#updateItem(T)) () dan (). transactWriteItems](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))

Misalnya, bayangkan Anda ingin menyimpan stempel waktu yang *dibuat pada* catatan Anda. Namun, Anda ingin nilainya ditulis hanya jika tidak ada nilai yang ada untuk atribut yang sudah ada dalam database. Dalam hal ini, Anda menggunakan perilaku `[WRITE\$1IF\$1NOT\$1EXISTS](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html#WRITE_IF_NOT_EXISTS)` pembaruan.

Contoh berikut menunjukkan anotasi yang menambahkan perilaku ke `createdOn` atribut.

```
@DynamoDbBean
public class Customer extends GenericRecord {
    private String id;
    private Instant createdOn;

    @DynamoDbPartitionKey
    public String getId() { return this.id; }
    public void setId(String id) { this.name = id; }

    @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)
    public Instant getCreatedOn() { return this.createdOn; }    
    public void setCreatedOn(Instant createdOn) { this.createdOn = createdOn; }
}
```

Anda dapat mendeklarasikan perilaku pembaruan yang sama ketika Anda membangun skema tabel statis seperti yang ditunjukkan pada contoh berikut setelah baris komentar 1.

```
static final TableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
     TableSchema.builder(Customer.class)
       .newItemSupplier(Customer::new)
       .addAttribute(String.class, a -> a.name("id")
                                         .getter(Customer::getId)
                                         .setter(Customer::setId)
                                         .tags(StaticAttributeTags.primaryPartitionKey()))
       .addAttribute(Instant.class, a -> a.name("createdOn")
                                          .getter(Customer::getCreatedOn)
                                          .setter(Customer::setCreatedOn)
                                          // 1. Add an UpdateBehavior.
                                          .tags(StaticAttributeTags.updateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)))
       .build();
```

# Ratakan atribut dari kelas lain
<a name="ddb-en-client-adv-features-flatmap"></a>

Jika atribut untuk tabel Anda tersebar di beberapa kelas Java yang berbeda, baik melalui pewarisan atau komposisi, DynamoDB Enhanced Client API menyediakan dukungan untuk meratakan atribut menjadi satu kelas.

## Gunakan warisan
<a name="ddb-en-client-adv-features-flatmap-inheritance"></a>

Jika kelas Anda menggunakan pewarisan, gunakan pendekatan berikut untuk meratakan hierarki.

### Gunakan kacang beranotasi
<a name="ddb-en-client-adv-features-flatmap-inheritance-anno"></a>

Untuk pendekatan anotasi, kedua kelas harus membawa `@DynamoDbBean` anotasi dan kelas harus membawa satu atau lebih anotasi kunci primer.

Berikut ini menunjukkan contoh kelas data yang memiliki hubungan warisan.

------
#### [ Standard data class ]

```
@DynamoDbBean
public class Customer extends GenericRecord {
    private String name;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

@DynamoDbBean
public abstract class GenericRecord {
    private String id;
    private String createdDate;

    @DynamoDbPartitionKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getCreatedDate() { return createdDate; }
    public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
}
```

------
#### [ Lombok ]

[`onMethod`Opsi](https://projectlombok.org/features/experimental/onX) Lombok menyalin anotasi DynamoDB berbasis atribut, seperti, ke kode yang dihasilkan. `@DynamoDbPartitionKey`

```
@DynamoDbBean
@Data
@ToString(callSuper = true)
public class Customer extends GenericRecord {
    private String name;
}

@Data
@DynamoDbBean
public abstract class GenericRecord {
    @Getter(onMethod_=@DynamoDbPartitionKey)
    private String id;
    private String createdDate;
}
```

------

### Gunakan skema statis
<a name="ddb-en-client-adv-features-flatmap-inheritance-static"></a>

Untuk pendekatan skema statis, gunakan `extend()` metode pembangun untuk menciutkan atribut kelas induk ke kelas anak. Ini ditampilkan setelah komentar baris 1 dalam contoh berikut.

```
        StaticTableSchema<org.example.tests.model.inheritance.stat.GenericRecord> GENERIC_RECORD_SCHEMA =
                StaticTableSchema.builder(org.example.tests.model.inheritance.stat.GenericRecord.class)
                        // The partition key will be inherited by the top level mapper.
                        .addAttribute(String.class, a -> a.name("id")
                                .getter(org.example.tests.model.inheritance.stat.GenericRecord::getId)
                                .setter(org.example.tests.model.inheritance.stat.GenericRecord::setId)
                                .tags(primaryPartitionKey()))
                        .addAttribute(String.class, a -> a.name("created_date")
                                .getter(org.example.tests.model.inheritance.stat.GenericRecord::getCreatedDate)
                                .setter(org.example.tests.model.inheritance.stat.GenericRecord::setCreatedDate))
                        .build();

        StaticTableSchema<org.example.tests.model.inheritance.stat.Customer> CUSTOMER_SCHEMA =
                StaticTableSchema.builder(org.example.tests.model.inheritance.stat.Customer.class)
                        .newItemSupplier(org.example.tests.model.inheritance.stat.Customer::new)
                        .addAttribute(String.class, a -> a.name("name")
                                .getter(org.example.tests.model.inheritance.stat.Customer::getName)
                                .setter(org.example.tests.model.inheritance.stat.Customer::setName))
                        // 1. Use the extend() method to collapse the parent attributes onto the child class.
                        .extend(GENERIC_RECORD_SCHEMA)     // All the attributes of the GenericRecord schema are added to Customer.
                        .build();
```

Contoh skema statis sebelumnya menggunakan kelas data berikut. Karena pemetaan didefinisikan ketika Anda membangun skema tabel statis, kelas data tidak memerlukan anotasi.

#### Kelas data
<a name="gunk"></a>

------
#### [ Standard data class ]

```
public class Customer extends GenericRecord {
    private String name;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}


public abstract class GenericRecord {
    private String id;
    private String createdDate;

    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getCreatedDate() { return createdDate; }
    public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
```

------
#### [ Lombok ]

```
@Data
@ToString(callSuper = true)
public class Customer extends GenericRecord{
    private String name;
}

@Data
public abstract class GenericRecord {
    private String id;
    private String createdDate;
}
```

------

## Gunakan komposisi
<a name="ddb-en-client-adv-features-flatmap-comp"></a>

Jika kelas Anda menggunakan komposisi, gunakan pendekatan berikut untuk meratakan hierarki.

### Gunakan kacang beranotasi
<a name="ddb-en-client-adv-features-flatmap-comp-anno"></a>

`@DynamoDbFlatten`Anotasi meratakan kelas yang terkandung.

Contoh kelas data berikut menggunakan `@DynamoDbFlatten` anotasi untuk secara efektif menambahkan semua atribut kelas yang terkandung ke `GenericRecord` `Customer` kelas.

------
#### [ Standard data class ]

```
@DynamoDbBean
public class Customer {
    private String name;
    private GenericRecord record;

    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }

    @DynamoDbFlatten
    public GenericRecord getRecord() { return this.record; }
    public void setRecord(GenericRecord record) { this.record = record; }

@DynamoDbBean
public class GenericRecord {
    private String id;
    private String createdDate;

    @DynamoDbPartitionKey
    public String getId() { return this.id; }
    public void setId(String id) { this.id = id; }

    public String getCreatedDate() { return this.createdDate; }
    public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
}
```

------
#### [ Lombok ]

```
@Data
@DynamoDbBean
public class Customer {
    private String name;
    @Getter(onMethod_=@DynamoDbFlatten)
    private GenericRecord record;
}

@Data
@DynamoDbBean
public class GenericRecord {
    @Getter(onMethod_=@DynamoDbPartitionKey)
    private String id;
    private String createdDate;
}
```

------

Anda dapat menggunakan anotasi rata untuk meratakan sebanyak mungkin kelas yang memenuhi syarat yang Anda butuhkan. Batasan berikut berlaku:
+ Semua nama atribut harus unik setelah diratakan.
+ Tidak boleh ada lebih dari satu kunci partisi, kunci sortir, atau nama tabel.

### Gunakan skema statis
<a name="ddb-en-client-adv-features-flatmap-comp-static"></a>

Saat Anda membuat skema tabel statis, gunakan `flatten()` metode pembangun. Anda juga menyediakan metode pengambil dan penyetel yang mengidentifikasi kelas yang terkandung.

```
        StaticTableSchema<GenericRecord> GENERIC_RECORD_SCHEMA =
                StaticTableSchema.builder(GenericRecord.class)
                        .newItemSupplier(GenericRecord::new)
                        .addAttribute(String.class, a -> a.name("id")
                                .getter(GenericRecord::getId)
                                .setter(GenericRecord::setId)
                                .tags(primaryPartitionKey()))
                        .addAttribute(String.class, a -> a.name("created_date")
                                .getter(GenericRecord::getCreatedDate)
                                .setter(GenericRecord::setCreatedDate))
                        .build();

        StaticTableSchema<Customer> CUSTOMER_SCHEMA =
                StaticTableSchema.builder(Customer.class)
                        .newItemSupplier(Customer::new)
                        .addAttribute(String.class, a -> a.name("name")
                                .getter(Customer::getName)
                                .setter(Customer::setName))
                        // Because we are flattening a component object, we supply a getter and setter so the
                        // mapper knows how to access it.
                        .flatten(GENERIC_RECORD_SCHEMA, Customer::getRecord, Customer::setRecord)
                        .build();
```

Contoh skema statis sebelumnya menggunakan kelas data berikut.

#### Kelas data
<a name="ddb-en-client-adv-features-flatmap-comp-static-supporting"></a>

------
#### [ Standard data class ]

```
public class Customer {
    private String name;
    private GenericRecord record;

    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }

    public GenericRecord getRecord() { return this.record; }
    public void setRecord(GenericRecord record) { this.record = record; }

public class GenericRecord {
    private String id;
    private String createdDate;

    public String getId() { return this.id; }
    public void setId(String id) { this.id = id; }

    public String getCreatedDate() { return this.createdDate; }
    public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
}
```

------
#### [ Lombok ]

```
@Data
public class Customer {
    private String name;
    private GenericRecord record;
}

@Data
public class GenericRecord {
    private String id;
    private String createdDate;
}
```

------

Anda dapat menggunakan pola pembangun untuk meratakan sebanyak mungkin kelas yang memenuhi syarat yang Anda butuhkan.

## Implikasi untuk kode lain
<a name="ddb-en-client-adv-features-flatmap-compare"></a>

Bila Anda menggunakan `@DynamoDbFlatten` atribut (atau metode `flatten()` builder), item di DynamoDB berisi atribut untuk setiap atribut dari objek yang disusun. Ini juga mencakup atribut dari objek penulisan. 

Sebaliknya, jika Anda membuat anotasi kelas data dengan kelas tersusun dan tidak menggunakan`@DynamoDbFlatten`, item disimpan dengan objek tersusun sebagai atribut tunggal.

Misalnya, bandingkan `Customer` kelas yang ditunjukkan dalam [perataan dengan contoh komposisi dengan](#ddb-en-client-adv-features-flatmap-comp-anno) dan tanpa perataan atribut. `record` Anda dapat memvisualisasikan perbedaannya dengan JSON seperti yang ditunjukkan pada tabel berikut.


****  

| Dengan perataan | Tanpa perataan | 
| --- | --- | 
| 3 atribut | 2 atribut | 
|  <pre>{<br />  "id": "1",<br />  "createdDate": "today",<br />  "name": "my name"<br />}</pre>  |  <pre>{<br />  "id": "1",<br />  "record": {<br />      "createdDate": "today",<br />      "name": "my name"<br />  }<br />}</pre>  | 

Perbedaannya menjadi penting jika Anda memiliki kode lain yang mengakses tabel DynamoDB yang mengharapkan untuk menemukan atribut tertentu.

# Bekerja dengan atribut yang kacang, peta, daftar, dan set
<a name="ddb-en-client-adv-features-nested"></a>

Definisi kacang, seperti `Person` kelas yang ditunjukkan di bawah ini, mungkin mendefinisikan properti (atau atribut) yang merujuk ke tipe dengan atribut tambahan. Misalnya, di `Person` kelas, `mainAddress` adalah properti yang mengacu pada `Address` kacang yang mendefinisikan atribut nilai tambahan. `addresses`mengacu pada Peta Jawa, yang unsur-unsurnya mengacu pada `Address` kacang. Tipe kompleks ini dapat dianggap sebagai wadah atribut sederhana yang Anda gunakan untuk nilai datanya dalam konteks DynamoDB. 

*DynamoDB mengacu pada properti nilai elemen bersarang, seperti peta, daftar, atau kacang, sebagai atribut bersarang.* *Panduan [Pengembang Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) mengacu pada bentuk yang disimpan dari peta Java, daftar atau kacang sebagai jenis dokumen.* Atribut sederhana yang Anda gunakan untuk nilai data mereka di Java disebut sebagai *tipe skalar* di DynamoDB. Set, yang berisi beberapa elemen skalar dari jenis yang sama, dan disebut sebagai *tipe set*. 

Penting untuk diketahui bahwa DynamoDB Enhanced Client API mengonversi properti yang bean ke jenis dokumen peta DynamoDB saat disimpan.

## `Person` kelas
<a name="ddb-en-client-adv-features-nested-person"></a>

```
@DynamoDbBean
public class Person {
    private Integer id;
    private String firstName;
    private String lastName;
    private Integer age;
    private Address mainAddress;
    private Map<String, Address> addresses;
    private List<PhoneNumber> phoneNumbers;
    private Set<String> hobbies;

    @DynamoDbPartitionKey
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Address getMainAddress() {
        return mainAddress;
    }

    public void setMainAddress(Address mainAddress) {
        this.mainAddress = mainAddress;
    }

    public Map<String, Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(Map<String, Address> addresses) {
        this.addresses = addresses;
    }

    public List<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }

    public Set<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(Set<String> hobbies) {
        this.hobbies = hobbies;
    }

    @Override
    public String toString() {
        return "Person{" +
               "addresses=" + addresses +
               ", id=" + id +
               ", firstName='" + firstName + '\'' +
               ", lastName='" + lastName + '\'' +
               ", age=" + age +
               ", mainAddress=" + mainAddress +
               ", phoneNumbers=" + phoneNumbers +
               ", hobbies=" + hobbies +
               '}';
    }
}
```

## `Address` kelas
<a name="ddb-en-client-adv-features-nested-address"></a>

```
@DynamoDbBean
public class Address {
    private String street;
    private String city;
    private String state;
    private String zipCode;

    public Address() {
    }

    public String getStreet() {
        return this.street;
    }

    public String getCity() {
        return this.city;
    }

    public String getState() {
        return this.state;
    }

    public String getZipCode() {
        return this.zipCode;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public void setState(String state) {
        this.state = state;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return Objects.equals(street, address.street) && Objects.equals(city, address.city) && Objects.equals(state, address.state) && Objects.equals(zipCode, address.zipCode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(street, city, state, zipCode);
    }

    @Override
    public String toString() {
        return "Address{" +
                "street='" + street + '\'' +
                ", city='" + city + '\'' +
                ", state='" + state + '\'' +
                ", zipCode='" + zipCode + '\'' +
                '}';
    }
}
```

## `PhoneNumber` kelas
<a name="ddb-en-client-adv-features-nested-phonenumber"></a>

```
@DynamoDbBean
public class PhoneNumber {
    String type;
    String number;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "PhoneNumber{" +
                "type='" + type + '\'' +
                ", number='" + number + '\'' +
                '}';
    }
}
```

## Simpan tipe kompleks
<a name="ddb-en-client-adv-features-nested-mapping"></a>

### Gunakan kelas data beranotasi
<a name="ddb-en-client-adv-features-nested-map-anno"></a>

Anda menyimpan atribut bersarang untuk kelas khusus hanya dengan membuat anotasi. `Address`Kelas dan `PhoneNumber` kelas yang ditampilkan sebelumnya dianotasi hanya dengan anotasi. `@DynamoDbBean` Saat DynamoDB Enhanced Client API membangun skema tabel untuk `Person` kelas dengan cuplikan berikut, API akan menemukan penggunaan class `PhoneNumber` dan dan membangun pemetaan yang sesuai agar berfungsi dengan DynamoDB. `Address`

```
TableSchema<Person> personTableSchema = TableSchema.fromBean(Person.class);
```

### Gunakan skema abstrak dengan pembangun
<a name="ddb-en-client-adv-features-nested-map-builder"></a>

Pendekatan alternatifnya adalah dengan menggunakan pembangun skema tabel statis untuk setiap kelas kacang bersarang seperti yang ditunjukkan pada kode berikut.

Skema tabel untuk `PhoneNumber` kelas `Address` dan abstrak dalam arti bahwa mereka tidak dapat digunakan dengan tabel DynamoDB. Ini karena mereka tidak memiliki definisi untuk kunci utama. Mereka digunakan, bagaimanapun, sebagai skema bersarang dalam skema tabel untuk kelas. `Person`

Setelah baris komentar 1 dan 2 dalam definisi`PERSON_TABLE_SCHEMA`, Anda melihat kode yang menggunakan skema tabel abstrak. Penggunaan `documentOf` dalam `EnhanceType.documentOf(...)` metode tidak menunjukkan bahwa metode mengembalikan `EnhancedDocument` jenis API Dokumen yang Ditingkatkan. `documentOf(...)`Metode dalam konteks ini mengembalikan objek yang tahu bagaimana memetakan argumen kelasnya ke dan dari DynamoDB atribut tabel dengan menggunakan argumen skema tabel.

#### Kode skema statis
<a name="ddb-en-client-adv-features-nested-map-builder-code"></a>

```
    // Abstract table schema that cannot be used to work with a DynamoDB table,
    // but can be used as a nested schema.
    public static final TableSchema<Address> TABLE_SCHEMA_ADDRESS = TableSchema.builder(Address.class)
        .newItemSupplier(Address::new)
        .addAttribute(String.class, a -> a.name("street")
            .getter(Address::getStreet)
            .setter(Address::setStreet))
        .addAttribute(String.class, a -> a.name("city")
            .getter(Address::getCity)
            .setter(Address::setCity))
        .addAttribute(String.class, a -> a.name("zipcode")
            .getter(Address::getZipCode)
            .setter(Address::setZipCode))
        .addAttribute(String.class, a -> a.name("state")
            .getter(Address::getState)
            .setter(Address::setState))
        .build();

    // Abstract table schema that cannot be used to work with a DynamoDB table,
    // but can be used as a nested schema.
    public static final TableSchema<PhoneNumber> TABLE_SCHEMA_PHONENUMBER = TableSchema.builder(PhoneNumber.class)
        .newItemSupplier(PhoneNumber::new)
        .addAttribute(String.class, a -> a.name("type")
            .getter(PhoneNumber::getType)
            .setter(PhoneNumber::setType))
        .addAttribute(String.class, a -> a.name("number")
            .getter(PhoneNumber::getNumber)
            .setter(PhoneNumber::setNumber))
        .build();

    // A static table schema that can be used with a DynamoDB table.
    // The table schema contains two nested schemas that are used to perform mapping to/from DynamoDB.
    public static final TableSchema<Person> PERSON_TABLE_SCHEMA =
        TableSchema.builder(Person.class)
            .newItemSupplier(Person::new)
            .addAttribute(Integer.class, a -> a.name("id")
                .getter(Person::getId)
                .setter(Person::setId)
                .addTag(StaticAttributeTags.primaryPartitionKey()))
            .addAttribute(String.class, a -> a.name("firstName")
                .getter(Person::getFirstName)
                .setter(Person::setFirstName))
            .addAttribute(String.class, a -> a.name("lastName")
                .getter(Person::getLastName)
                .setter(Person::setLastName))
            .addAttribute(Integer.class, a -> a.name("age")
                .getter(Person::getAge)
                .setter(Person::setAge))
            .addAttribute(EnhancedType.documentOf(Address.class, TABLE_SCHEMA_ADDRESS), a -> a.name("mainAddress")
                .getter(Person::getMainAddress)
                .setter(Person::setMainAddress))
            .addAttribute(EnhancedType.listOf(String.class), a -> a.name("hobbies")
                .getter(Person::getHobbies)
                .setter(Person::setHobbies))
            .addAttribute(EnhancedType.mapOf(
                EnhancedType.of(String.class),
                // 1. Use mapping functionality of the Address table schema.
                EnhancedType.documentOf(Address.class, TABLE_SCHEMA_ADDRESS)), a -> a.name("addresses")
                .getter(Person::getAddresses)
                .setter(Person::setAddresses))
            .addAttribute(EnhancedType.listOf(
                // 2. Use mapping functionality of the PhoneNumber table schema.
                EnhancedType.documentOf(PhoneNumber.class, TABLE_SCHEMA_PHONENUMBER)), a -> a.name("phoneNumbers")
                .getter(Person::getPhoneNumbers)
                .setter(Person::setPhoneNumbers))
            .build();
```

## Atribut proyek dari tipe kompleks
<a name="ddb-en-client-adv-features-nested-projection"></a>

Untuk `query()` dan `scan()` metode, Anda dapat menentukan atribut mana yang ingin Anda kembalikan dalam hasil dengan menggunakan panggilan metode seperti `addNestedAttributeToProject()` dan`attributesToProject()`. DynamoDB Enhanced Client API mengubah parameter panggilan metode Java [menjadi ekspresi proyeksi sebelum permintaan dikirim](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html).

Contoh berikut mengisi `Person` tabel dengan dua item, kemudian melakukan tiga operasi pemindaian. 

Pemindaian pertama mengakses semua item dalam tabel untuk membandingkan hasilnya dengan operasi pemindaian lainnya. 

Pemindaian kedua menggunakan metode [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#addNestedAttributeToProject(software.amazon.awssdk.enhanced.dynamodb.NestedAttributeName)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#addNestedAttributeToProject(software.amazon.awssdk.enhanced.dynamodb.NestedAttributeName))builder untuk mengembalikan hanya nilai `street` atribut.

Operasi pemindaian ketiga menggunakan metode [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#attributesToProject(java.lang.String...)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#attributesToProject(java.lang.String...))builder untuk mengembalikan data untuk atribut tingkat pertama,`hobbies`. Jenis atribut `hobbies` adalah daftar. Untuk mengakses item daftar individual, lakukan `get()` operasi pada daftar.

```
        personDynamoDbTable = getDynamoDbEnhancedClient().table("Person", PERSON_TABLE_SCHEMA);
        PersonUtils.createPersonTable(personDynamoDbTable, getDynamoDbClient());
        // Use a utility class to add items to the Person table.
        List<Person> personList = PersonUtils.getItemsForCount(2);
        // This utility method performs a put against DynamoDB to save the instances in the list argument.
        PersonUtils.putCollection(getDynamoDbEnhancedClient(), personList, personDynamoDbTable);

        // The first scan logs all items in the table to compare to the results of the subsequent scans.
        final PageIterable<Person> allItems = personDynamoDbTable.scan();
        allItems.items().forEach(p ->
                // 1. Log what is in the table.
                logger.info(p.toString()));

        // Scan for nested attributes.
        PageIterable<Person> streetScanResult = personDynamoDbTable.scan(b -> b
                // Use the 'addNestedAttributeToProject()' or 'addNestedAttributesToProject()' to access data nested in maps in DynamoDB.
                .addNestedAttributeToProject(
                        NestedAttributeName.create("addresses", "work", "street")
                ));

        streetScanResult.items().forEach(p ->
                //2. Log the results of requesting nested attributes.
                logger.info(p.toString()));

        // Scan for a top-level list attribute.
        PageIterable<Person> hobbiesScanResult = personDynamoDbTable.scan(b -> b
                // Use the 'attributesToProject()' method to access first-level attributes.
                .attributesToProject("hobbies"));

        hobbiesScanResult.items().forEach((p) -> {
            // 3. Log the results of the request for the 'hobbies' attribute.
            logger.info(p.toString());
            // To access an item in a list, first get the parent attribute, 'hobbies', then access items in the list.
            String hobby = p.getHobbies().get(1);
            // 4. Log an item in the list.
            logger.info(hobby);
        });
```

```
// Logged results from comment line 1.
Person{id=2, firstName='first name 2', lastName='last name 2', age=11, addresses={work=Address{street='street 21', city='city 21', state='state 21', zipCode='33333'}, home=Address{street='street 2', city='city 2', state='state 2', zipCode='22222'}}, phoneNumbers=[PhoneNumber{type='home', number='222-222-2222'}, PhoneNumber{type='work', number='333-333-3333'}], hobbies=[hobby 2, hobby 21]}
Person{id=1, firstName='first name 1', lastName='last name 1', age=11, addresses={work=Address{street='street 11', city='city 11', state='state 11', zipCode='22222'}, home=Address{street='street 1', city='city 1', state='state 1', zipCode='11111'}}, phoneNumbers=[PhoneNumber{type='home', number='111-111-1111'}, PhoneNumber{type='work', number='222-222-2222'}], hobbies=[hobby 1, hobby 11]}

// Logged results from comment line 2.
Person{id=null, firstName='null', lastName='null', age=null, addresses={work=Address{street='street 21', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=null}
Person{id=null, firstName='null', lastName='null', age=null, addresses={work=Address{street='street 11', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=null}

// Logged results from comment lines 3 and 4.
Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 2, hobby 21]}
hobby 21
Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 1, hobby 11]}
hobby 11
```

**catatan**  
Jika `attributesToProject()` metode mengikuti metode pembangun lain yang menambahkan atribut yang ingin Anda proyeksikan, daftar nama atribut yang diberikan ke `attributesToProject()` menggantikan semua nama atribut lainnya.  
Pemindaian yang dilakukan dengan `ScanEnhancedRequest` instance dalam cuplikan berikut hanya mengembalikan data hobi.  

```
ScanEnhancedRequest lastOverwrites = ScanEnhancedRequest.builder()
        .addNestedAttributeToProject(
                NestedAttributeName.create("addresses", "work", "street"))
        .addAttributeToProject("firstName")
        // If the 'attributesToProject()' method follows other builder methods that add attributes for projection,
        // its list of attributes replace all previous attributes.
        .attributesToProject("hobbies")
        .build();
PageIterable<Person> hobbiesOnlyResult = personDynamoDbTable.scan(lastOverwrites);
hobbiesOnlyResult.items().forEach(p ->
        logger.info(p.toString()));

// Logged results.
Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 2, hobby 21]}
Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 1, hobby 11]}
```
Cuplikan kode berikut menggunakan `attributesToProject()` metode terlebih dahulu. Urutan ini mempertahankan semua atribut lain yang diminta.  

```
ScanEnhancedRequest attributesPreserved = ScanEnhancedRequest.builder()
        // Use 'attributesToProject()' first so that the method call does not replace all other attributes
        // that you want to project.
        .attributesToProject("firstName")
        .addNestedAttributeToProject(
                NestedAttributeName.create("addresses", "work", "street"))
        .addAttributeToProject("hobbies")
        .build();
PageIterable<Person> allAttributesResult = personDynamoDbTable.scan(attributesPreserved);
allAttributesResult.items().forEach(p ->
        logger.info(p.toString()));

// Logged results.
Person{id=null, firstName='first name 2', lastName='null', age=null, addresses={work=Address{street='street 21', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=[hobby 2, hobby 21]}
Person{id=null, firstName='first name 1', lastName='null', age=null, addresses={work=Address{street='street 11', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=[hobby 1, hobby 11]}
```

## Gunakan tipe kompleks dalam ekspresi
<a name="ddb-en-client-adv-features-nested-expressions"></a>

Anda dapat menggunakan tipe kompleks dalam ekspresi, seperti ekspresi filter dan ekspresi kondisi, dengan menggunakan operator dereferencing untuk menavigasi struktur tipe kompleks. Untuk objek dan peta, gunakan `. (dot)` dan untuk elemen daftar gunakan `[n]` (tanda kurung siku di sekitar nomor urut elemen). Anda tidak dapat merujuk ke elemen individual dari satu set, tetapi Anda dapat menggunakan [`contains`fungsi](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) tersebut.

Contoh berikut menunjukkan dua ekspresi filter yang digunakan dalam operasi scan. Ekspresi filter menentukan kondisi kecocokan untuk item yang Anda inginkan dalam hasil. Contoh menggunakan`Person`,`Address`, dan `PhoneNumber` kelas yang ditampilkan sebelumnya.

```
    public void scanUsingFilterOfNestedAttr() {
        // The following is a filter expression for an attribute that is a map of Address objects.
        // By using this filter expression, the SDK returns Person objects that have an address
        // with 'mailing' as a key and 'MS2' for a state value.
        Expression addressFilter = Expression.builder()
                .expression("addresses.#type.#field = :value")
                .putExpressionName("#type", "mailing")
                .putExpressionName("#field", "state")
                .putExpressionValue(":value", AttributeValue.builder().s("MS2").build())
                .build();

        PageIterable<Person> addressFilterResults = personDynamoDbTable.scan(rb -> rb.
                filterExpression(addressFilter));
        addressFilterResults.items().stream().forEach(p -> logger.info("Person: {}", p));

        assert addressFilterResults.items().stream().count() == 1;


        // The following is a filter expression for an attribute that is a list of phone numbers.
        // By using this filter expression, the SDK returns Person objects whose second phone number
        // in the list has a type equal to 'cell'.
        Expression phoneFilter = Expression.builder()
                .expression("phoneNumbers[1].#type = :type")
                .putExpressionName("#type", "type")
                .putExpressionValue(":type", AttributeValue.builder().s("cell").build())
                .build();

        PageIterable<Person> phoneFilterResults = personDynamoDbTable.scan(rb -> rb
                .filterExpression(phoneFilter)
                .attributesToProject("id", "firstName", "lastName", "phoneNumbers")
        );

        phoneFilterResults.items().stream().forEach(p -> logger.info("Person: {}", p));

        assert phoneFilterResults.items().stream().count() == 1;
        assert phoneFilterResults.items().stream().findFirst().get().getPhoneNumbers().get(1).getType().equals("cell");
    }
```

### Metode pembantu yang mengisi tabel
<a name="nested-expressions-helper-method"></a>

```
    public static void populateDatabase() {
        Person person1 = new Person();
        person1.setId(1);
        person1.setFirstName("FirstName1");
        person1.setLastName("LastName1");

        Address billingAddr1 = new Address();
        billingAddr1.setState("BS1");
        billingAddr1.setCity("BillingTown1");

        Address mailing1 = new Address();
        mailing1.setState("MS1");
        mailing1.setCity("MailingTown1");

        person1.setAddresses(Map.of("billing", billingAddr1, "mailing", mailing1));

        PhoneNumber pn1_1 = new PhoneNumber();
        pn1_1.setType("work");
        pn1_1.setNumber("111-111-1111");

        PhoneNumber pn1_2 = new PhoneNumber();
        pn1_2.setType("home");
        pn1_2.setNumber("222-222-2222");

        List<PhoneNumber> phoneNumbers1 = List.of(pn1_1, pn1_2);
        person1.setPhoneNumbers(phoneNumbers1);

        personDynamoDbTable.putItem(person1);

        Person person2 = person1;
        person2.setId(2);
        person2.setFirstName("FirstName2");
        person2.setLastName("LastName2");

        Address billingAddress2 = billingAddr1;
        billingAddress2.setCity("BillingTown2");
        billingAddress2.setState("BS2");

        Address mailing2 = mailing1;
        mailing2.setCity("MailingTown2");
        mailing2.setState("MS2");

        person2.setAddresses(Map.of("billing", billingAddress2, "mailing", mailing2));

        PhoneNumber pn2_1 = new PhoneNumber();
        pn2_1.setType("work");
        pn2_1.setNumber("333-333-3333");

        PhoneNumber pn2_2 = new PhoneNumber();
        pn2_2.setType("cell");
        pn2_2.setNumber("444-444-4444");

        List<PhoneNumber> phoneNumbers2 = List.of(pn2_1, pn2_2);
        person2.setPhoneNumbers(phoneNumbers2);

        personDynamoDbTable.putItem(person2);
    }
```

### Representasi JSON item dalam database
<a name="nested-attributes-expression-json-items"></a>

```
{
 "id": 1,
 "addresses": {
  "billing": {
   "city": "BillingTown1",
   "state": "BS1",
   "street": null,
   "zipCode": null
  },
  "mailing": {
   "city": "MailingTown1",
   "state": "MS1",
   "street": null,
   "zipCode": null
  }
 },
 "firstName": "FirstName1",
 "lastName": "LastName1",
 "phoneNumbers": [
  {
   "number": "111-111-1111",
   "type": "work"
  },
  {
   "number": "222-222-2222",
   "type": "home"
  }
 ]
}

{
 "id": 2,
 "addresses": {
  "billing": {
   "city": "BillingTown2",
   "state": "BS2",
   "street": null,
   "zipCode": null
  },
  "mailing": {
   "city": "MailingTown2",
   "state": "MS2",
   "street": null,
   "zipCode": null
  }
 },
 "firstName": "FirstName2",
 "lastName": "LastName2",
 "phoneNumbers": [
  {
   "number": "333-333-3333",
   "type": "work"
  },
  {
   "number": "444-444-4444",
   "type": "cell"
  }
 ]
}
```

## Perbarui item yang berisi tipe kompleks
<a name="ddb-en-client-adv-features-nested-updates"></a>

Untuk memperbarui item yang berisi tipe kompleks, Anda memiliki dua pendekatan dasar:
+ Pendekatan 1: Pertama ambil item (dengan menggunakan`getItem`), perbarui objek, lalu panggil`DynamoDbTable#updateItem`.
+ Pendekatan 2: Jangan mengambil item, tetapi buat instance baru, atur properti yang ingin Anda perbarui, dan kirimkan instance `DynamoDbTable#updateItem` dengan menyetel nilai yang sesuai dari. [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html) Pendekatan ini tidak mengharuskan Anda mengambil item sebelum memperbaruinya.

Contoh yang ditunjukkan di bagian ini menggunakan`Person`,`Address`, dan `PhoneNumber` kelas yang ditunjukkan sebelumnya.

### Perbarui pendekatan 1: ambil, lalu perbarui
<a name="ddb-en-client-adv-features-nested-updates-retreive"></a>

Dengan menggunakan pendekatan ini, Anda memastikan bahwa tidak ada data yang hilang pada pembaruan. DynamoDB Enhanced Client API membuat ulang bean dengan atribut dari item yang disimpan di DynamoDB termasuk nilai tipe kompleks. Anda kemudian perlu menggunakan getter dan setter untuk memperbarui kacang. Kelemahan dari pendekatan ini adalah biaya yang Anda keluarkan untuk mengambil item terlebih dahulu.

Contoh berikut menunjukkan bahwa tidak ada data yang hilang jika Anda pertama kali mengambil item sebelum memperbaruinya.

```
    public void retrieveThenUpdateExample()  {
        // Assume that we ran this code yesterday.
        Person person = new Person();
        person.setId(1);
        person.setFirstName("FirstName");
        person.setLastName("LastName");

        Address mainAddress = new Address();
        mainAddress.setStreet("123 MyStreet");
        mainAddress.setCity("MyCity");
        mainAddress.setState("MyState");
        mainAddress.setZipCode("MyZipCode");
        person.setMainAddress(mainAddress);

        PhoneNumber homePhone = new PhoneNumber();
        homePhone.setNumber("1111111");
        homePhone.setType("HOME");
        person.setPhoneNumbers(List.of(homePhone));

        personDynamoDbTable.putItem(person);

        // Assume that we are running this code now.
        // First, retrieve the item
        Person retrievedPerson = personDynamoDbTable.getItem(Key.builder().partitionValue(1).build());

        // Make any updates.
        retrievedPerson.getMainAddress().setCity("YourCity");

        // Save the updated bean. 'updateItem' returns the bean as it appears after the update.
        Person updatedPerson = personDynamoDbTable.updateItem(retrievedPerson);

        // Verify for this example.
        Address updatedMainAddress = updatedPerson.getMainAddress();
        assert updatedMainAddress.getCity().equals("YourCity");
        assert updatedMainAddress.getState().equals("MyState"); // Unchanged.
        // The list of phone numbers remains; it was not set to null;
        assert updatedPerson.getPhoneNumbers().size() == 1;
    }
```

### Pendekatan pembaruan 2: Gunakan `IgnoreNullsMode` enum tanpa mengambil item terlebih dahulu
<a name="ddb-en-client-adv-features-nested-updates-nullmode"></a>

Untuk memperbarui item di DynamoDB, Anda dapat memberikan objek baru yang hanya memiliki properti yang ingin diperbarui dan membiarkan nilai lainnya sebagai null. Dengan pendekatan ini, Anda perlu mengetahui bagaimana nilai nol dalam objek diperlakukan oleh SDK dan bagaimana Anda dapat mengontrol perilaku.

Untuk menentukan properti bernilai nol mana yang ingin diabaikan oleh SDK, berikan `IgnoreNullsMode` enum saat Anda membuat. [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/UpdateItemEnhancedRequest.Builder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/UpdateItemEnhancedRequest.Builder.html) Sebagai contoh menggunakan salah satu nilai yang disebutkan, cuplikan berikut menggunakan mode. `IgnoreNullsMode.SCALAR_ONLY`

```
// Create a new Person object to update the existing item in DynamoDB.
Person personForUpdate = new Person();
personForUpdate.setId(1);
personForUpdate.setFirstName("updatedFirstName");  // 'firstName' is a top scalar property.

Address addressForUpdate = new Address();
addressForUpdate.setCity("updatedCity");
personForUpdate.setMainAddress(addressForUpdate);

personDynamoDbTable.updateItem(r -> r
                .item(personForUpdate)
                .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY));

/* With IgnoreNullsMode.SCALAR_ONLY provided, The SDK ignores all null properties. The SDK adds or replaces
the 'firstName' property with the provided value, "updatedFirstName". The SDK updates the 'city' value of
'mainAddress', as long as the 'mainAddress' attribute already exists in DynamoDB.

In the background, the SDK generates an update expression that it sends in the request to DynamoDB.
The following JSON object is a simplified version of what it sends. Notice that the SDK includes the paths
to 'mainAddress.city' and 'firstName' in the SET clause of the update expression. No null values in
'personForUpdate' are included.

{
  "TableName": "PersonTable",
  "Key": {
    "id": {
      "N": "1"
    }
  },
  "ReturnValues": "ALL_NEW",
  "UpdateExpression": "SET #mainAddress.#city = :mainAddress_city, #firstName = :firstName",
  "ExpressionAttributeNames": {
    "#city": "city",
    "#firstName": "firstName",
    "#mainAddress": "mainAddress"
  },
  "ExpressionAttributeValues": {
    ":firstName": {
      "S": "updatedFirstName"
    },
    ":mainAddress_city": {
      "S": "updatedCity"
    }
  }
}

Had we chosen 'IgnoreNullsMode.DEFAULT' instead of 'IgnoreNullsMode.SCALAR_ONLY', the SDK would have included
null values in the "ExpressionAttributeValues" section of the request as shown in the following snippet.

  "ExpressionAttributeValues": {
    ":mainAddress": {
      "M": {
        "zipCode": {
          "NULL": true
        },
        "city": {
          "S": "updatedCity"
        },
        "street": {
          "NULL": true
        },
        "state": {
          "NULL": true
        }
      }
    },
    ":firstName": {
      "S": "updatedFirstName"
    }
  }
*/
```

[Panduan Pengembang Amazon DynamoDB berisi informasi lebih lanjut tentang ekspresi pembaruan.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html)

#### Deskripsi opsi `IgnoreNullsMode`
<a name="ignore-nulls-mode-descriptions"></a>
+ `IgnoreNullsMode.SCALAR_ONLY`- Gunakan pengaturan ini untuk memperbarui atribut skalar di tingkat manapun. SDK membuat pernyataan pembaruan yang hanya mengirimkan atribut skalar non-null ke DynamoDB. SDK mengabaikan atribut skalar bernilai nol dari kacang atau peta, mempertahankan nilai yang disimpan di DynamoDB.

  Saat Anda memperbarui atribut skalar map atau bean, peta harus sudah ada di DynamoDB. Jika Anda menambahkan peta atau kacang ke objek yang belum ada untuk objek di DynamoDB, Anda mendapatkan dengan *pesan Jalur dokumen `DynamoDbException` yang disediakan dalam ekspresi pembaruan tidak valid untuk pembaruan*. Anda harus menggunakan `MAPS_ONLY` mode untuk menambahkan kacang atau peta ke DynamoDB sebelum Anda memperbarui salah satu atributnya.
+ `IgnoreNullsMode.MAPS_ONLY`- Gunakan pengaturan ini untuk menambah atau mengganti properti yang merupakan kacang atau peta. SDK menggantikan atau menambahkan peta atau kacang apa pun yang disediakan dalam objek. Setiap kacang atau peta yang null dalam objek diabaikan, mempertahankan peta yang ada di DynamoDB.
+ `IgnoreNullsMode.DEFAULT`- Dengan pengaturan ini, SDK tidak pernah mengabaikan nilai null. Atribut skalar pada tingkat manapun yang null diperbarui ke null. SDK memperbarui properti bean, map, list, atau set bernilai nol dalam objek ke null di DynamoDB. Saat Anda menggunakan mode ini—atau tidak menyediakan mode karena ini adalah mode default—Anda harus mengambil item terlebih dahulu sehingga nilai di DynamoDB tidak disetel ke null yang disediakan dalam objek untuk diperbarui, kecuali niat Anda adalah untuk mengatur nilai ke null.

Dalam semua mode, jika Anda memberikan objek `updateItem` yang memiliki daftar atau set non-null, daftar atau set disimpan ke DynamoDB. 

#### Mengapa mode?
<a name="ddb-en-client-adv-features-nested-updates-nullmodes-why"></a>

Saat Anda memberikan objek dengan kacang atau peta ke `updateItem` metode, SDK tidak dapat mengetahui apakah objek tersebut harus menggunakan nilai properti dalam kacang (atau nilai entri di peta) untuk memperbarui item, atau apakah keseluruhan bean/map harus menggantikan apa yang telah disimpan ke DynamoDB.

Bekerja dari contoh sebelumnya yang menunjukkan pengambilan item terlebih dahulu, mari kita coba memperbarui `city` atribut `mainAddress` tanpa pengambilan.

```
/* The retrieval example saved the Person object with a 'mainAddress' property whose 'city' property value is "MyCity".
/* Note that we create a new Person with only the necessary information to update the city value
of the mainAddress. */
Person personForUpdate = new Person();
personForUpdate.setId(1);
// The update we want to make changes the city.
Address mainAddressForUpdate = new Address();
mainAddressForUpdate.setCity("YourCity");
personForUpdate.setMainAddress(mainAddressForUpdate);

// Lets' try the following:
Person updatedPerson = personDynamoDbTable.updateItem(personForUpdate);
/*
 Since we haven't retrieved the item, we don't know if the 'mainAddress' property
 already exists, so what update expression should the SDK generate?

A) Should it replace or add the 'mainAddress' with the provided object (setting all attributes to null other than city)
   as shown in the following simplified JSON?

      {
        "TableName": "PersonTable",
        "Key": {
          "id": {
            "N": "1"
          }
        },
        "ReturnValues": "ALL_NEW",
        "UpdateExpression": "SET #mainAddress = :mainAddress",
        "ExpressionAttributeNames": {
          "#mainAddress": "mainAddress"
        },
        "ExpressionAttributeValues": {
          ":mainAddress": {
            "M": {
              "zipCode": {
                "NULL": true
              },
              "city": {
                "S": "YourCity"
              },
              "street": {
                "NULL": true
              },
              "state": {
                "NULL": true
              }
            }
          }
        }
      }
 
B) Or should it update only the 'city' attribute of an existing 'mainAddress' as shown in the following simplified JSON?

      {
        "TableName": "PersonTable",
        "Key": {
          "id": {
            "N": "1"
          }
        },
        "ReturnValues": "ALL_NEW",
        "UpdateExpression": "SET #mainAddress.#city = :mainAddress_city",
        "ExpressionAttributeNames": {
          "#city": "city",
          "#mainAddress": "mainAddress"
        },
        "ExpressionAttributeValues": {
          ":mainAddress_city": {
            "S": "YourCity"
          }
        }
      }

However, assume that we don't know if the 'mainAddress' already exists. If it doesn't exist, the SDK would try to update 
an attribute of a non-existent map, which results in an exception.

In this particular case, we would likely select option B (SCALAR_ONLY) to retain the other values of the 'mainAddress'.
*/
```

Dua contoh berikut menunjukkan penggunaan nilai `MAPS_ONLY` dan `SCALAR_ONLY` enumerasi. `MAPS_ONLY`menambahkan peta dan `SCALAR_ONLY` memperbarui peta.

##### Contoh `IgnoreNullsMode.MAPS_ONLY`
<a name="scalar-only-example"></a>

```
    public void mapsOnlyModeExample() {
        // Assume that we ran this code yesterday.
        Person person = new Person();
        person.setId(1);
        person.setFirstName("FirstName");

        personDynamoDbTable.putItem(person);

        // Assume that we are running this code now.

        /* Note that we create a new Person with only the necessary information to update the city value
        of the mainAddress. */
        Person personForUpdate = new Person();
        personForUpdate.setId(1);
        // The update we want to make changes the city.
        Address mainAddressForUpdate = new Address();
        mainAddressForUpdate.setCity("YourCity");
        personForUpdate.setMainAddress(mainAddressForUpdate);


        Person updatedPerson = personDynamoDbTable.updateItem(r -> r
                .item(personForUpdate)
                .ignoreNullsMode(IgnoreNullsMode.MAPS_ONLY)); // Since the mainAddress property does not exist, use MAPS_ONLY mode.
        assert updatedPerson.getMainAddress().getCity().equals("YourCity");
        assert updatedPerson.getMainAddress().getState() == null;
    }
```

##### `IgnoreNullsMode.SCALAR_ONLY example`
<a name="maps-only-example"></a>

```
    public void scalarOnlyExample() {
        // Assume that we ran this code yesterday.
        Person person = new Person();
        person.setId(1);
        Address mainAddress = new Address();
        mainAddress.setCity("MyCity");
        mainAddress.setState("MyState");
        person.setMainAddress(mainAddress);

        personDynamoDbTable.putItem(person);

        // Assume that we are running this code now.

        /* Note that we create a new Person with only the necessary information to update the city value
        of the mainAddress. */
        Person personForUpdate = new Person();
        personForUpdate.setId(1);
        // The update we want to make changes the city.
        Address mainAddressForUpdate = new Address();
        mainAddressForUpdate.setCity("YourCity");
        personForUpdate.setMainAddress(mainAddressForUpdate);

        Person updatedPerson = personDynamoDbTable.updateItem(r -> r
                .item(personForUpdate)
                .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY)); // SCALAR_ONLY mode ignores null properties in the in mainAddress.
        assert updatedPerson.getMainAddress().getCity().equals("YourCity");
        assert updatedPerson.getMainAddress().getState().equals("MyState"); // The state property remains the same.
    }
```

Lihat tabel berikut untuk melihat nilai null mana yang diabaikan untuk setiap mode. Anda sering dapat bekerja dengan salah satu `SCALAR_ONLY` dan `MAPS_ONLY` kecuali ketika Anda bekerja dengan kacang atau peta.


**Properti bernilai nol mana dalam objek yang dikirimkan yang diabaikan SDK untuk `updateItem` setiap mode?**  

| Jenis properti | dalam mode SCALAR\$1ONLY | dalam mode MAPS\$1ONLY | dalam mode DEFAULT | 
| --- | --- | --- | --- | 
| Skalar teratas | Ya | Ya | Tidak | 
| Kacang atau peta | Ya | Ya | Tidak | 
| Nilai skalar entri kacang atau peta | Ya1 | Tidak 2 | Tidak | 
| Daftar atau set | Ya | Ya | Tidak | 

1 Ini mengasumsikan peta sudah ada di DynamoDB. Nilai skalar apa pun—null atau bukan null—dari kacang atau peta yang Anda berikan di objek untuk pembaruan mengharuskan jalur ke nilai ada di DynamoDB. SDK membuat jalur ke atribut dengan menggunakan operator `. (dot)` dereference sebelum mengirimkan permintaan.

2 Karena Anda menggunakan `MAPS_ONLY` mode untuk sepenuhnya mengganti atau menambahkan kacang atau peta, semua nilai nol dalam kacang atau peta dipertahankan di peta yang disimpan ke DynamoDB.

# Pertahankan benda kosong dengan `@DynamoDbPreserveEmptyObject`
<a name="ddb-en-client-adv-features-empty"></a>

Jika Anda menyimpan kacang ke Amazon DynamoDB dengan objek kosong dan Anda ingin SDK membuat ulang objek kosong saat pengambilan, beri anotasi pengambil kacang bagian dalam dengan. `@DynamoDbPreserveEmptyObject`

Untuk mengilustrasikan cara kerja anotasi, contoh kode menggunakan dua kacang berikut.

## Contoh kacang
<a name="ddb-en-client-adv-features-empty-ex1"></a>

Kelas data berikut berisi dua `InnerBean` bidang. Metode getter,`getInnerBeanWithoutAnno()`, tidak dijelaskan dengan. `@DynamoDbPreserveEmptyObject` `getInnerBeanWithAnno()`Metode ini dijelaskan.

```
@DynamoDbBean
public class MyBean {

    private String id;
    private String name;
    private InnerBean innerBeanWithoutAnno;
    private InnerBean innerBeanWithAnno;

    @DynamoDbPartitionKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public InnerBean getInnerBeanWithoutAnno() { return innerBeanWithoutAnno; }
    public void setInnerBeanWithoutAnno(InnerBean innerBeanWithoutAnno) { this.innerBeanWithoutAnno = innerBeanWithoutAnno; }

    @DynamoDbPreserveEmptyObject
    public InnerBean getInnerBeanWithAnno() { return innerBeanWithAnno; }
    public void setInnerBeanWithAnno(InnerBean innerBeanWithAnno) { this.innerBeanWithAnno = innerBeanWithAnno; }

    @Override
    public String toString() {
        return new StringJoiner(", ", MyBean.class.getSimpleName() + "[", "]")
                .add("innerBeanWithoutAnno=" + innerBeanWithoutAnno)
                .add("innerBeanWithAnno=" + innerBeanWithAnno)
                .add("id='" + id + "'")
                .add("name='" + name + "'")
                .toString();
    }
}
```

Contoh dari `InnerBean` kelas berikut adalah bidang `MyBean` dan diinisialisasi sebagai objek kosong dalam kode contoh.

```
@DynamoDbBean
public class InnerBean {

    private String innerBeanField;

    public String getInnerBeanField() {
        return innerBeanField;
    }

    public void setInnerBeanField(String innerBeanField) {
        this.innerBeanField = innerBeanField;
    }

    @Override
    public String toString() {
        return "InnerBean{" +
                "innerBeanField='" + innerBeanField + '\'' +
                '}';
    }
}
```

Contoh kode berikut menyimpan `MyBean` objek dengan kacang dalam yang diinisialisasi ke DynamoDB dan kemudian mengambil item tersebut. Output yang dicatat menunjukkan bahwa tidak `innerBeanWithoutAnno` diinisialisasi, tetapi `innerBeanWithAnno` telah dibuat.

```
    public MyBean preserveEmptyObjectAnnoUsingGetItemExample(DynamoDbTable<MyBean> myBeanTable) {
        // Save an item to DynamoDB.
        MyBean bean = new MyBean();
        bean.setId("1");
        bean.setInnerBeanWithoutAnno(new InnerBean());   // Instantiate the inner bean.
        bean.setInnerBeanWithAnno(new InnerBean());      // Instantiate the inner bean.
        myBeanTable.putItem(bean);

        GetItemEnhancedRequest request = GetItemEnhancedRequest.builder()
                .key(Key.builder().partitionValue("1").build())
                .build();
        MyBean myBean = myBeanTable.getItem(request);

        logger.info(myBean.toString());
        // Output 'MyBean[innerBeanWithoutAnno=null, innerBeanWithAnno=InnerBean{innerBeanField='null'}, id='1', name='null']'.

        return myBean;
    }
```

## Skema statis alternatif
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

Anda dapat menggunakan `StaticTableSchema` versi skema tabel berikut sebagai pengganti anotasi pada kacang.

```
    public static TableSchema<MyBean> buildStaticSchemas() {

        StaticTableSchema<InnerBean> innerBeanStaticTableSchema =
                StaticTableSchema.builder(InnerBean.class)
                        .newItemSupplier(InnerBean::new)
                        .addAttribute(String.class, a -> a.name("innerBeanField")
                                .getter(InnerBean::getInnerBeanField)
                                .setter(InnerBean::setInnerBeanField))
                        .build();

        return StaticTableSchema.builder(MyBean.class)
                .newItemSupplier(MyBean::new)
                .addAttribute(String.class, a -> a.name("id")
                        .getter(MyBean::getId)
                        .setter(MyBean::setId)
                        .addTag(primaryPartitionKey()))
                .addAttribute(String.class, a -> a.name("name")
                        .getter(MyBean::getName)
                        .setter(MyBean::setName))
                .addAttribute(EnhancedType.documentOf(InnerBean.class,
                                innerBeanStaticTableSchema),
                        a -> a.name("innerBean1")
                                .getter(MyBean::getInnerBeanWithoutAnno)
                                .setter(MyBean::setInnerBeanWithoutAnno))
                .addAttribute(EnhancedType.documentOf(InnerBean.class,
                                innerBeanStaticTableSchema,
                                b -> b.preserveEmptyObject(true)),
                        a -> a.name("innerBean2")
                                .getter(MyBean::getInnerBeanWithAnno)
                                .setter(MyBean::setInnerBeanWithAnno))
                .build();
    }
```

# Hindari menyimpan atribut null dari objek bersarang
<a name="ddb-en-client-adv-features-ignore-null"></a>

Anda dapat melewati atribut null dari objek bersarang saat menyimpan objek kelas data ke DynamoDB dengan menerapkan anotasi. `@DynamoDbIgnoreNulls` Sebaliknya, atribut tingkat atas dengan nilai null tidak pernah disimpan ke database.

Untuk mengilustrasikan cara kerja anotasi, contoh kode menggunakan dua kacang berikut.

## Contoh kacang
<a name="ddb-en-client-adv-features-ignore-null-ex1"></a>

Kelas data berikut berisi dua `InnerBean` bidang. Metode getter,`getInnerBeanWithoutAnno()`, tidak dijelaskan. `getInnerBeanWithIgnoreNullsAnno()`Metode ini dianotasi dengan. `@DynamoDbIgnoreNulls`

```
@DynamoDbBean
public class MyBean {

    private String id;
    private String name;
    private InnerBean innerBeanWithoutAnno;
    private InnerBean innerBeanWithIgnoreNullsAnno;

    @DynamoDbPartitionKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public InnerBean getInnerBeanWithoutAnno() { return innerBeanWithoutAnno; }
    public void setInnerBeanWithoutAnno(InnerBean innerBeanWithoutAnno) { this.innerBeanWithoutAnno = innerBeanWithoutAnno; }

    @DynamoDbIgnoreNulls
    public InnerBean getInnerBeanWithIgnoreNullsAnno() { return innerBeanWithIgnoreNullsAnno; }
    public void setInnerBeanWithIgnoreNullsAnno(InnerBean innerBeanWithAnno) { this.innerBeanWithIgnoreNullsAnno = innerBeanWithAnno; }

    @Override
    public String toString() {
        return new StringJoiner(", ", MyBean.class.getSimpleName() + "[", "]")
                .add("innerBeanWithoutAnno=" + innerBeanWithoutAnno)
                .add("innerBeanWithIgnoreNullsAnno=" + innerBeanWithIgnoreNullsAnno)
                .add("id='" + id + "'")
                .add("name='" + name + "'")
                .toString();
    }
}
```

Contoh dari `InnerBean` kelas berikut adalah bidang `MyBean` dan digunakan dalam kode contoh berikut.

```
@DynamoDbBean
public class InnerBean {

    private String innerBeanFieldString;
    private Integer innerBeanFieldInteger;

    public String getInnerBeanFieldString() { return innerBeanFieldString; }
    public void setInnerBeanFieldString(String innerBeanFieldString) { this.innerBeanFieldString = innerBeanFieldString; }

    public Integer getInnerBeanFieldInteger() { return innerBeanFieldInteger; }
    public void setInnerBeanFieldInteger(Integer innerBeanFieldInteger) { this.innerBeanFieldInteger = innerBeanFieldInteger; }

    @Override
    public String toString() {
        return new StringJoiner(", ", InnerBean.class.getSimpleName() + "[", "]")
                .add("innerBeanFieldString='" + innerBeanFieldString + "'")
                .add("innerBeanFieldInteger=" + innerBeanFieldInteger)
                .toString();
    }
}
```

Contoh kode berikut menciptakan `InnerBean` objek dan menetapkan hanya satu dari dua atribut dengan nilai. 

```
    public void ignoreNullsAnnoUsingPutItemExample(DynamoDbTable<MyBean> myBeanTable) {
        // Create an InnerBean object and give only one attribute a value.
        InnerBean innerBeanOneAttributeSet = new InnerBean();
        innerBeanOneAttributeSet.setInnerBeanFieldInteger(200);

        // Create a MyBean instance and use the same InnerBean instance both for attributes.
        MyBean bean = new MyBean();
        bean.setId("1");
        bean.setInnerBeanWithoutAnno(innerBeanOneAttributeSet);
        bean.setInnerBeanWithIgnoreNullsAnno(innerBeanOneAttributeSet);

        Map<String, AttributeValue> itemMap = myBeanTable.tableSchema().itemToMap(bean, true);
        logger.info(itemMap.toString());
        // Log the map that is sent to the database.
        // {innerBeanWithIgnoreNullsAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200)}), id=AttributeValue(S=1), innerBeanWithoutAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200), innerBeanFieldString=AttributeValue(NUL=true)})}
        
        // Save the MyBean object to the table.
        myBeanTable.putItem(bean);
    }
```

Untuk memvisualisasikan data tingkat rendah yang dikirim ke DynamoDB, kode mencatat peta atribut sebelum menyimpan objek. `MyBean`

Output yang dicatat menunjukkan bahwa `innerBeanWithIgnoreNullsAnno` output satu atribut,

```
innerBeanWithIgnoreNullsAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200)})
```

`innerBeanWithoutAnno`Instance menghasilkan dua atribut. Satu atribut memiliki nilai 200 dan yang lainnya adalah atribut bernilai nol.

```
innerBeanWithoutAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200), innerBeanFieldString=AttributeValue(NUL=true)})
```

## Representasi JSON dari peta atribut
<a name="ddb-en-client-adv-features-ignore-null-ex2"></a>

Representasi JSON berikut membuatnya lebih mudah untuk melihat data yang disimpan ke DynamoDB.

```
{
  "id": {
    "S": "1"
  },
  "innerBeanWithIgnoreNullsAnno": {
    "M": {
      "innerBeanFieldInteger": {
        "N": "200"
      }
    }
  },
  "innerBeanWithoutAnno": {
    "M": {
      "innerBeanFieldInteger": {
        "N": "200"
      },
      "innerBeanFieldString": {
        "NULL": true
      }
    }
  }
}
```

## Skema statis alternatif
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

Anda dapat menggunakan `StaticTableSchema` versi berikut dari skema tabel di tempat anotasi kelas data.

```
public static TableSchema<MyBean> buildStaticSchemas() {

    StaticTableSchema<InnerBean> innerBeanStaticTableSchema =
        StaticTableSchema.builder(InnerBean.class)
            .newItemSupplier(InnerBean::new)
            .addAttribute(String.class, a -> a.name("innerBeanFieldString")
                .getter(InnerBean::getInnerBeanFieldString)
                .setter(InnerBean::setInnerBeanFieldString))
            .addAttribute(Integer.class, a -> a.name("innerBeanFieldInteger")
                .getter(InnerBean::getInnerBeanFieldInteger)
                .setter(InnerBean::setInnerBeanFieldInteger))
            .build();

    return StaticTableSchema.builder(MyBean.class)
        .newItemSupplier(MyBean::new)
        .addAttribute(String.class, a -> a.name("id")
            .getter(MyBean::getId)
            .setter(MyBean::setId)
            .addTag(primaryPartitionKey()))
        .addAttribute(String.class, a -> a.name("name")
            .getter(MyBean::getName)
            .setter(MyBean::setName))
        .addAttribute(EnhancedType.documentOf(InnerBean.class,
                innerBeanStaticTableSchema),
            a -> a.name("innerBeanWithoutAnno")
                .getter(MyBean::getInnerBeanWithoutAnno)
                .setter(MyBean::setInnerBeanWithoutAnno))
        .addAttribute(EnhancedType.documentOf(InnerBean.class,
                innerBeanStaticTableSchema,
                b -> b.ignoreNulls(true)),
            a -> a.name("innerBeanWithIgnoreNullsAnno")
                .getter(MyBean::getInnerBeanWithIgnoreNullsAnno)
                .setter(MyBean::setInnerBeanWithIgnoreNullsAnno))
        .build();
}
```

# Bekerja dengan dokumen JSON dengan Enhanced Document API untuk DynamoDB
<a name="ddb-en-client-doc-api"></a>

[Enhanced Document API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) for AWS SDK for Java 2.x dirancang untuk bekerja dengan data berorientasi dokumen yang tidak memiliki skema tetap. Namun, ini juga memungkinkan Anda menggunakan kelas khusus untuk memetakan atribut individual.

 Enhanced Document API adalah penerus [Document API](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html) dari AWS SDK untuk Java v1.x.

**Contents**
+ [Mulai menggunakan Enhanced Document API](ddb-en-client-doc-api-steps.md)
  + [Buat `DocumentTableSchema` dan a `DynamoDbTable`](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema)
+ [Membangun dokumen yang disempurnakan](ddb-en-client-doc-api-steps-create-ed.md)
  + [Membangun dari string JSON](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromJson)
  + [Membangun dari elemen individu](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts)
+ [Lakukan operasi CRUD](ddb-en-client-doc-api-steps-use.md)
+ [Akses atribut dokumen yang disempurnakan sebagai objek khusus](ddb-en-client-doc-api-convert.md)
+ [Gunakan `EnhancedDocument` tanpa DynamoDB](ddb-en-client-doc-api-standalone.md)

# Mulai menggunakan Enhanced Document API
<a name="ddb-en-client-doc-api-steps"></a>

Enhanced Document API memerlukan [dependensi](ddb-en-client-getting-started.md#ddb-en-client-gs-dep) yang sama yang diperlukan untuk DynamoDB Enhanced Client API. Ini juga membutuhkan [`DynamoDbEnhancedClient`contoh](ddb-en-client-getting-started-dynamodbTable.md#ddb-en-client-getting-started-dynamodbTable-eclient) seperti yang ditunjukkan di awal topik ini.

Karena API Dokumen yang Ditingkatkan dirilis dengan versi 2.20.3 AWS SDK for Java 2.x, Anda memerlukan versi itu atau lebih tinggi.

## Buat `DocumentTableSchema` dan a `DynamoDbTable`
<a name="ddb-en-client-doc-api-steps-createschema"></a>

Untuk menjalankan perintah terhadap tabel DynamoDB menggunakan Enhanced Document API, kaitkan tabel dengan objek resource < > sisi [DynamoDbTableklien EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html). 

`table()`Metode klien yang disempurnakan membuat `DynamoDbTable<EnhancedDocument>` instance dan membutuhkan parameter untuk nama tabel DynamoDB dan a. `DocumentTableSchema` 

Pembangun untuk a [DocumentTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/DocumentTableSchema.html)memerlukan kunci indeks utama dan satu atau lebih penyedia konverter atribut. `AttributeConverterProvider.defaultProvider()`Metode ini menyediakan konverter untuk [tipe default](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/package-summary.html). Itu harus ditentukan bahkan jika Anda menyediakan penyedia konverter atribut khusus. Anda dapat menambahkan kunci indeks sekunder opsional ke pembangun.

Cuplikan kode berikut menunjukkan kode yang menghasilkan representasi sisi klien dari tabel DynamoDB yang menyimpan objek tanpa skema. `person` `EnhancedDocument`

```
DynamoDbTable<EnhancedDocument> documentDynamoDbTable = 
                enhancedClient.table("person",
                        TableSchema.documentSchemaBuilder()
                            // Specify the primary key attributes.
                            .addIndexPartitionKey(TableMetadata.primaryIndexName(),"id", AttributeValueType.S)
                            .addIndexSortKey(TableMetadata.primaryIndexName(), "lastName", AttributeValueType.S)
                            // Specify attribute converter providers. Minimally add the default one.
                            .attributeConverterProviders(AttributeConverterProvider.defaultProvider())
                            .build());
                                                         
// Call documentTable.createTable() if "person" does not exist in DynamoDB.
// createTable() should be called only one time.
```

Berikut ini menunjukkan representasi JSON dari `person` objek yang digunakan di seluruh bagian ini.

### Objek JSON `person`
<a name="ddb-en-client-doc-api-steps-createschema-obj"></a>

```
{
  "id": 1,
  "firstName": "Richard",
  "lastName": "Roe",
  "age": 25,
  "addresses":
    {
      "home": {
        "zipCode": "00000",
        "city": "Any Town",
        "state": "FL",
        "street": "123 Any Street"
      },
      "work": {
        "zipCode": "00001",
        "city": "Anywhere",
        "state": "FL",
        "street": "100 Main Street"
      }
    },
  "hobbies": [
    "Hobby 1",
    "Hobby 2"
  ],
  "phoneNumbers": [
    {
      "type": "Home",
      "number": "555-0100"
    },
    {
      "type": "Work",
      "number": "555-0119"
    }
  ]
}
```

# Membangun dokumen yang disempurnakan
<a name="ddb-en-client-doc-api-steps-create-ed"></a>

An `[EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html)` merupakan objek tipe dokumen yang memiliki struktur kompleks dengan atribut bersarang. Sebuah `EnhancedDocument` membutuhkan atribut tingkat atas yang cocok dengan atribut kunci utama yang ditentukan untuk atribut. `DocumentTableSchema` Konten yang tersisa bersifat arbitrer dan dapat terdiri dari atribut tingkat atas dan juga atribut yang sangat bersarang.

Anda membuat `EnhancedDocument` instance dengan menggunakan builder yang menyediakan beberapa cara untuk menambahkan elemen.

## Membangun dari string JSON
<a name="ddb-en-client-doc-api-steps-create-ed-fromJson"></a>

Dengan string JSON, Anda dapat membangun panggilan `EnhancedDocument` dalam satu metode. Cuplikan berikut membuat `EnhancedDocument` dari string JSON dikembalikan oleh metode helper. `jsonPerson()` `jsonPerson()`Metode mengembalikan versi string JSON dari [objek orang](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema-obj) yang ditunjukkan sebelumnya.

```
EnhancedDocument document = 
        EnhancedDocument.builder()
                        .json( jsonPerson() )
                        .build());
```

## Membangun dari elemen individu
<a name="ddb-en-client-doc-api-steps-create-ed-fromparts"></a>

Atau, Anda dapat membangun sebuah `EnhancedDocument` instance dari komponen individual menggunakan metode type-safe dari builder.

Contoh berikut membangun dokumen yang `person` disempurnakan mirip dengan dokumen yang disempurnakan yang dibangun dari string JSON pada contoh sebelumnya.

```
        /* Define the shape of an address map whose JSON representation looks like the following.
           Use 'addressMapEnhancedType' in the following EnhancedDocument.builder() to simplify the code.
           "home": {
             "zipCode": "00000",
             "city": "Any Town",
             "state": "FL",
             "street": "123 Any Street"
           }*/
        EnhancedType<Map<String, String>> addressMapEnhancedType =
                EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.of(String.class));


        //  Use the builder's typesafe methods to add elements to the enhanced document.
        EnhancedDocument personDocument = EnhancedDocument.builder()
                .putNumber("id", 50)
                .putString("firstName", "Shirley")
                .putString("lastName", "Rodriguez")
                .putNumber("age", 53)
                .putNull("nullAttribute")
                .putJson("phoneNumbers", phoneNumbersJSONString())
                /* Add the map of addresses whose JSON representation looks like the following.
                        {
                          "home": {
                            "zipCode": "00000",
                            "city": "Any Town",
                            "state": "FL",
                            "street": "123 Any Street"
                          }
                        } */
                .putMap("addresses", getAddresses(), EnhancedType.of(String.class), addressMapEnhancedType)
                .putList("hobbies", List.of("Theater", "Golf"), EnhancedType.of(String.class))
                .build();
```

### Metode pembantu
<a name="ddb-en-client-doc-api-steps-use-fromparts-helpers"></a>

```
    private static String phoneNumbersJSONString() {
        return "  [" +
                "    {" +
                "      \"type\": \"Home\"," +
                "      \"number\": \"555-0140\"" +
                "    }," +
                "    {" +
                "      \"type\": \"Work\"," +
                "      \"number\": \"555-0155\"" +
                "    }" +
                "  ]";
    }

    private static Map<String, Map<String, String>> getAddresses() {
        return Map.of(
                "home", Map.of(
                        "zipCode", "00002",
                        "city", "Any Town",
                        "state", "ME",
                        "street", "123 Any Street"));

    }
```

# Lakukan operasi CRUD
<a name="ddb-en-client-doc-api-steps-use"></a>

Setelah Anda mendefinisikan sebuah `EnhancedDocument` instance, Anda dapat menyimpannya ke tabel DynamoDB. Cuplikan kode berikut menggunakan [personDocument](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts) yang dibuat dari elemen individual.

```
documentDynamoDbTable.putItem(personDocument);
```

Setelah Anda membaca instance dokumen yang disempurnakan dari DynamoDB, Anda dapat mengekstrak nilai atribut individual menggunakan getter seperti yang ditunjukkan dalam cuplikan kode berikut yang mengakses data yang disimpan dari. `personDocument` Atau, Anda dapat mengekstrak konten lengkap ke string JSON seperti yang ditunjukkan pada bagian terakhir dari kode contoh.

```
        // Read the item.
        EnhancedDocument personDocFromDb = documentDynamoDbTable.getItem(Key.builder().partitionValue(50).build());

        // Access top-level attributes.
        logger.info("Name: {} {}", personDocFromDb.getString("firstName"), personDocFromDb.getString("lastName"));
        // Name: Shirley Rodriguez

        // Typesafe access of a deeply nested attribute. The addressMapEnhancedType shown previously defines the shape of an addresses map.
        Map<String, Map<String, String>> addresses = personDocFromDb.getMap("addresses", EnhancedType.of(String.class), addressMapEnhancedType);
        addresses.keySet().forEach(k -> logger.info(addresses.get(k).toString()));
        // {zipCode=00002, city=Any Town, street=123 Any Street, state=ME}

        // Alternatively, work with AttributeValue types checking along the way for deeply nested attributes.
        Map<String, AttributeValue> addressesMap = personDocFromDb.getMapOfUnknownType("addresses");
        addressesMap.keySet().forEach((String k) -> {
            logger.info("Looking at data for [{}] address", k);
            // Looking at data for [home] address
            AttributeValue value = addressesMap.get(k);
            AttributeValue cityValue = value.m().get("city");
            if (cityValue != null) {
                logger.info(cityValue.s());
                // Any Town
            }
        });

        List<AttributeValue> phoneNumbers = personDocFromDb.getListOfUnknownType("phoneNumbers");
        phoneNumbers.forEach((AttributeValue av) -> {
            if (av.hasM()) {
                AttributeValue type = av.m().get("type");
                if (type.s() != null) {
                    logger.info("Type of phone: {}", type.s());
                    // Type of phone: Home
                    // Type of phone: Work
                }
            }
        });

        String jsonPerson = personDocFromDb.toJson();
        logger.info(jsonPerson);
        // {"firstName":"Shirley","lastName":"Rodriguez","addresses":{"home":{"zipCode":"00002","city":"Any Town","street":"123 Any Street","state":"ME"}},"hobbies":["Theater","Golf"],
        //     "id":50,"nullAttribute":null,"age":53,"phoneNumbers":[{"number":"555-0140","type":"Home"},{"number":"555-0155","type":"Work"}]}
```

`EnhancedDocument`instance dapat digunakan dengan metode apa pun dari `[DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)` atau [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html)di tempat kelas data yang dipetakan.

# Akses atribut dokumen yang disempurnakan sebagai objek khusus
<a name="ddb-en-client-doc-api-convert"></a>

Selain menyediakan API untuk membaca dan menulis atribut dengan struktur tanpa skema, API Dokumen yang Ditingkatkan memungkinkan Anda mengonversi atribut ke dan dari instance kelas khusus.

Enhanced Document API menggunakan `AttributeConverterProvider` s dan `AttributeConverter` s yang ditampilkan di bagian [konversi atribut kontrol](ddb-en-client-adv-features-conversion.md) sebagai bagian dari DynamoDB Enhanced Client API.

Dalam contoh berikut, kita menggunakan a `CustomAttributeConverterProvider` dengan `AddressConverter` kelas bersarang untuk mengkonversi `Address` objek. 

Contoh ini menunjukkan bahwa Anda dapat mencampur data dari kelas dan juga data dari struktur yang dibangun sesuai kebutuhan. Contoh ini juga menunjukkan bahwa kelas kustom dapat digunakan pada setiap tingkat struktur bersarang. `Address`Objek dalam contoh ini adalah nilai yang digunakan dalam peta.

```
    public static void attributeToAddressClassMappingExample(DynamoDbEnhancedClient enhancedClient, DynamoDbClient standardClient) {
        String tableName = "customer";

        // Define the DynamoDbTable for an enhanced document.
        // The schema builder provides methods for attribute converter providers and keys.
        DynamoDbTable<EnhancedDocument> documentDynamoDbTable = enhancedClient.table(tableName,
                DocumentTableSchema.builder()
                        // Add the CustomAttributeConverterProvider along with the default when you build the table schema.
                        .attributeConverterProviders(
                                List.of(
                                        new CustomAttributeConverterProvider(),
                                        AttributeConverterProvider.defaultProvider()))
                        .addIndexPartitionKey(TableMetadata.primaryIndexName(), "id", AttributeValueType.N)
                        .addIndexSortKey(TableMetadata.primaryIndexName(), "lastName", AttributeValueType.S)
                        .build());
        // Create the DynamoDB table if needed.
        documentDynamoDbTable.createTable();
        waitForTableCreation(tableName, standardClient);


        // The getAddressesForCustomMappingExample() helper method that provides 'addresses' shows the use of a custom Address class
        // rather than using a Map<String, Map<String, String> to hold the address data.
        Map<String, Address> addresses = getAddressesForCustomMappingExample();

        // Build an EnhancedDocument instance to save an item with a mix of structures defined as needed and static classes.
        EnhancedDocument personDocument = EnhancedDocument.builder()
                .putNumber("id", 50)
                .putString("firstName", "Shirley")
                .putString("lastName", "Rodriguez")
                .putNumber("age", 53)
                .putNull("nullAttribute")
                .putJson("phoneNumbers", phoneNumbersJSONString())
                // Note the use of 'EnhancedType.of(Address.class)' instead of the more generic
                // 'EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.of(String.class))' that was used in a previous example.
                .putMap("addresses", addresses, EnhancedType.of(String.class), EnhancedType.of(Address.class))
                .putList("hobbies", List.of("Hobby 1", "Hobby 2"), EnhancedType.of(String.class))
                .build();
        // Save the item to DynamoDB.
        documentDynamoDbTable.putItem(personDocument);

        // Retrieve the item just saved.
        EnhancedDocument srPerson = documentDynamoDbTable.getItem(Key.builder().partitionValue(50).sortValue("Rodriguez").build());

        // Access the addresses attribute.
        Map<String, Address> srAddresses = srPerson.get("addresses",
                EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.of(Address.class)));

        srAddresses.keySet().forEach(k -> logger.info(addresses.get(k).toString()));

        documentDynamoDbTable.deleteTable();

// The content logged to the console shows that the saved maps were converted to Address instances.
Address{street='123 Main Street', city='Any Town', state='NC', zipCode='00000'}
Address{street='100 Any Street', city='Any Town', state='NC', zipCode='00000'}
```

## `CustomAttributeConverterProvider`kode
<a name="ddb-en-client-doc-api-convert-provider"></a>

```
public class CustomAttributeConverterProvider implements AttributeConverterProvider {

    private final Map<EnhancedType<?>, AttributeConverter<?>> converterCache = ImmutableMap.of(
            // 1. Add AddressConverter to the internal cache.
            EnhancedType.of(Address.class), new AddressConverter());

    public static CustomAttributeConverterProvider create() {
        return new CustomAttributeConverterProvider();
    }

    // 2. The enhanced client queries the provider for attribute converters if it
    //    encounters a type that it does not know how to convert.
    @SuppressWarnings("unchecked")
    @Override
    public <T> AttributeConverter<T> converterFor(EnhancedType<T> enhancedType) {
        return (AttributeConverter<T>) converterCache.get(enhancedType);
    }

    // 3. Custom attribute converter
    private class AddressConverter implements AttributeConverter<Address> {
        // 4. Transform an Address object into a DynamoDB map.
        @Override
        public AttributeValue transformFrom(Address address) {

            Map<String, AttributeValue> attributeValueMap = Map.of(
                    "street", AttributeValue.fromS(address.getStreet()),
                    "city", AttributeValue.fromS(address.getCity()),
                    "state", AttributeValue.fromS(address.getState()),
                    "zipCode", AttributeValue.fromS(address.getZipCode()));

            return AttributeValue.fromM(attributeValueMap);
        }

        // 5. Transform the DynamoDB map attribute to an Address oject.
        @Override
        public Address transformTo(AttributeValue attributeValue) {
            Map<String, AttributeValue> m = attributeValue.m();
            Address address = new Address();
            address.setStreet(m.get("street").s());
            address.setCity(m.get("city").s());
            address.setState(m.get("state").s());
            address.setZipCode(m.get("zipCode").s());

            return address;
        }

        @Override
        public EnhancedType<Address> type() {
            return EnhancedType.of(Address.class);
        }

        @Override
        public AttributeValueType attributeValueType() {
            return AttributeValueType.M;
        }
    }
}
```

## `Address` kelas
<a name="ddb-en-client-doc-api-convert-address"></a>

```
public class Address {
                  private String street;
                  private String city;
                  private String state;
                  private String zipCode;

                  public Address() {
                  }

                  public String getStreet() {
                  return this.street;
                  }

                  public String getCity() {
                  return this.city;
                  }

                  public String getState() {
                  return this.state;
                  }

                  public String getZipCode() {
                  return this.zipCode;
                  }

                  public void setStreet(String street) {
                  this.street = street;
                  }

                  public void setCity(String city) {
                  this.city = city;
                  }

                  public void setState(String state) {
                  this.state = state;
                  }

                  public void setZipCode(String zipCode) {
                  this.zipCode = zipCode;
                  }
                  }
```

## Metode pembantu yang menyediakan alamat
<a name="ddb-en-client-doc-api-convert-helper"></a>

Metode pembantu berikut menyediakan peta yang menggunakan `Address` instance kustom untuk nilai daripada `Map<String, String>` contoh generik untuk nilai.

```
    private static Map<String, Address> getAddressesForCustomMappingExample() {
        Address homeAddress = new Address();
        homeAddress.setStreet("100 Any Street");
        homeAddress.setCity("Any Town");
        homeAddress.setState("NC");
        homeAddress.setZipCode("00000");

        Address workAddress = new Address();
        workAddress.setStreet("123 Main Street");
        workAddress.setCity("Any Town");
        workAddress.setState("NC");
        workAddress.setZipCode("00000");

        return Map.of("home", homeAddress,
                "work", workAddress);
    }
```

# Gunakan `EnhancedDocument` tanpa DynamoDB
<a name="ddb-en-client-doc-api-standalone"></a>

Meskipun Anda biasanya menggunakan instance `EnhancedDocument` untuk membaca dan menulis item DynamoDB tipe dokumen, itu juga dapat digunakan secara independen dari DynamoDB. 

Anda dapat menggunakan kemampuan mereka `EnhancedDocuments` untuk mengkonversi antara string JSON atau objek kustom ke peta tingkat rendah `AttributeValues` seperti yang ditunjukkan dalam contoh berikut.

```
    public static void conversionWithoutDynamoDbExample() {
        Address address = new Address();
        address.setCity("my city");
        address.setState("my state");
        address.setStreet("my street");
        address.setZipCode("00000");

        // Build an EnhancedDocument instance for its conversion functionality alone.
        EnhancedDocument addressEnhancedDoc = EnhancedDocument.builder()
                // Important: You must specify attribute converter providers when you build an EnhancedDocument instance not used with a DynamoDB table.
                .attributeConverterProviders(new CustomAttributeConverterProvider(), DefaultAttributeConverterProvider.create())
                .put("addressDoc", address, Address.class)
                .build();

        // Convert address to a low-level item representation.
        final Map<String, AttributeValue> addressAsAttributeMap = addressEnhancedDoc.getMapOfUnknownType("addressDoc");
        logger.info("addressAsAttributeMap: {}", addressAsAttributeMap.toString());

        // Convert address to a JSON string.
        String addressAsJsonString = addressEnhancedDoc.getJson("addressDoc");
        logger.info("addressAsJsonString: {}", addressAsJsonString);
        // Convert addressEnhancedDoc back to an Address instance.
        Address addressConverted =  addressEnhancedDoc.get("addressDoc", Address.class);
        logger.info("addressConverted: {}", addressConverted.toString());
    }

   /* Console output:
          addressAsAttributeMap: {zipCode=AttributeValue(S=00000), state=AttributeValue(S=my state), street=AttributeValue(S=my street), city=AttributeValue(S=my city)}
          addressAsJsonString: {"zipCode":"00000","state":"my state","street":"my street","city":"my city"}
          addressConverted: Address{street='my street', city='my city', state='my state', zipCode='00000'}
   */
```

**catatan**  
Bila Anda menggunakan dokumen yang disempurnakan independen dari tabel DynamoDB, pastikan Anda secara eksplisit menetapkan penyedia konverter atribut pada pembangun.  
Sebaliknya, skema tabel dokumen memasok penyedia konverter ketika dokumen yang disempurnakan digunakan dengan tabel DynamoDB.

# Gunakan ekstensi untuk menyesuaikan operasi DynamoDB Enhanced Client
<a name="ddb-en-client-extensions"></a>

DynamoDB Enhanced Client API mendukung ekstensi plugin yang menyediakan fungsionalitas di luar operasi pemetaan. Ekstensi menggunakan dua metode hook untuk memodifikasi data selama operasi baca dan tulis:
+ `beforeWrite()`- Memodifikasi operasi tulis sebelum itu terjadi
+ `afterRead()`- Memodifikasi hasil operasi baca setelah itu terjadi

Beberapa operasi (seperti pembaruan item) melakukan penulisan dan kemudian membaca, sehingga kedua metode kait dipanggil.

## Bagaimana ekstensi dimuat
<a name="ddb-en-client-extensions-loading"></a>

Ekstensi dimuat dalam urutan yang Anda tentukan di pembuat klien yang disempurnakan. Urutan pemuatan dapat menjadi penting karena satu ekstensi dapat bertindak berdasarkan nilai yang telah diubah oleh ekstensi sebelumnya.

Secara default, klien yang disempurnakan memuat dua ekstensi:
+ `[VersionedRecordExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtension.html)`- Memberikan penguncian optimis
+ `[AtomicCounterExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/AtomicCounterExtension.html)`- Secara otomatis menambah atribut penghitung

Anda dapat mengganti perilaku default dengan pembuat klien yang disempurnakan dan memuat ekstensi apa pun. Anda juga dapat menentukan none jika Anda tidak ingin ekstensi default.

**penting**  
Jika Anda memuat ekstensi Anda sendiri, klien yang disempurnakan tidak memuat ekstensi default apa pun. Jika Anda menginginkan perilaku yang disediakan oleh salah satu ekstensi default, Anda perlu menambahkannya secara eksplisit ke daftar ekstensi.

Contoh berikut menunjukkan cara memuat ekstensi kustom yang `verifyChecksumExtension` dinamai`VersionedRecordExtension`. `AtomicCounterExtension`Tidak dimuat dalam contoh ini.

```
DynamoDbEnhancedClientExtension versionedRecordExtension = VersionedRecordExtension.builder().build();

DynamoDbEnhancedClient enhancedClient = 
    DynamoDbEnhancedClient.builder()
                          .dynamoDbClient(dynamoDbClient)
                          .extensions(versionedRecordExtension, verifyChecksumExtension)
                          .build();
```

## Detail dan konfigurasi ekstensi yang tersedia
<a name="ddb-en-client-extensions-details"></a>

Bagian berikut memberikan informasi rinci tentang setiap ekstensi yang tersedia di SDK.

### Terapkan penguncian optimis dengan `VersionedRecordExtension`
<a name="ddb-en-client-extensions-VRE"></a>

`VersionedRecordExtension`Ekstensi ini memberikan penguncian optimis dengan menambah dan melacak nomor versi item saat item ditulis ke database. Kondisi ditambahkan ke setiap penulisan yang menyebabkan penulisan gagal jika nomor versi item tetap yang sebenarnya tidak cocok dengan nilai yang terakhir dibaca aplikasi.

#### Konfigurasi
<a name="ddb-en-client-extensions-VRE-conf"></a>

Untuk menentukan atribut mana yang akan digunakan untuk melacak nomor versi item, beri tag atribut numerik dalam skema tabel.

Cuplikan berikut menentukan bahwa `version` atribut harus menyimpan nomor versi item.

```
    @DynamoDbVersionAttribute
    public Integer getVersion() {...};
    public void setVersion(Integer version) {...};
```

Pendekatan skema tabel statis setara ditunjukkan dalam cuplikan berikut.

```
    .addAttribute(Integer.class, a -> a.name("version")
                                       .getter(Customer::getVersion)
                                       .setter(Customer::setVersion)
                                        // Apply the 'version' tag to the attribute.
                                       .tags(VersionedRecordExtension.AttributeTags.versionAttribute())
```

#### Cara kerjanya
<a name="ddb-en-client-extensions-VRE-how-it-works"></a>

Penguncian optimis dengan `VersionedRecordExtension` memiliki dampak berikut pada ini `DynamoDbEnhancedClient` dan `DynamoDbTable` metode:

**`putItem`**  
Item baru diberi nilai versi awal 0. Ini dapat dikonfigurasi dengan`@DynamoDbVersionAttribute(startAt = X)`.

**`updateItem`**  
Jika Anda mengambil item, memperbarui satu atau beberapa propertinya, dan mencoba menyimpan perubahan, operasi hanya berhasil jika nomor versi di sisi klien dan sisi server cocok.  
Jika berhasil, nomor versi secara otomatis bertambah 1. Ini dapat dikonfigurasi dengan`@DynamoDbVersionAttribute(incrementBy = X)`.

**`deleteItem`**  
`DynamoDbVersionAttribute`Anotasi tidak berpengaruh. Anda harus menambahkan ekspresi kondisi secara manual saat menghapus item.  
Contoh berikut menambahkan ekspresi bersyarat untuk memastikan bahwa item yang dihapus adalah item yang telah dibaca. Dalam contoh berikut `recordVersion` adalah atribut kacang yang dianotasi dengan. `@DynamoDbVersionAttribute`  

```
// 1. Read the item and get its current version.
Customer item = customerTable.getItem(Key.builder().partitionValue("someId").build());
// `recordVersion` is the bean's attribute that is annotated with `@DynamoDbVersionAttribute`.
AttributeValue currentVersion = item.getRecordVersion();

// 2. Create conditional delete with the `currentVersion` value.
DeleteItemEnhancedRequest deleteItemRequest =
    DeleteItemEnhancedRequest.builder()
       .key(KEY)
       .conditionExpression(Expression.builder()
           .expression("recordVersion = :current_version_value")
           .putExpressionValue(":current_version_value", currentVersion)
           .build()).build();

customerTable.deleteItem(deleteItemRequest);
```

**`transactWriteItems`**  
+ `addPutItem`: Metode ini memiliki perilaku yang sama dengan`putItem`.
+ `addUpdateItem`: Metode ini memiliki perilaku yang sama dengan`updateItem`.
+ `addDeleteItem`: Metode ini memiliki perilaku yang sama dengan`deleteItem`.

**`batchWriteItem`**  
+ `addPutItem`: Metode ini memiliki perilaku yang sama dengan`putItem`.
+ `addDeleteItem`: Metode ini memiliki perilaku yang sama dengan`deleteItem`.

**catatan**  
Tabel global DynamoDB menggunakan rekonsiliasi ['penulis terakhir menang'](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/V2globaltables_HowItWorks.html#V2globaltables_HowItWorks.consistency-modes) antara pembaruan bersamaan, di mana DynamoDB melakukan upaya terbaik untuk menentukan penulis terakhir. Jika Anda menggunakan tabel global, kebijakan 'penulis terakhir menang' ini berarti bahwa strategi penguncian mungkin tidak berfungsi seperti yang diharapkan, karena semua replika pada akhirnya akan bertemu berdasarkan penulisan terakhir yang ditentukan oleh DynamoDB. 

#### Cara menonaktifkan
<a name="ddb-en-client-extensions-VRE-how-to-disable"></a>

Untuk menonaktifkan penguncian optimis, jangan gunakan `@DynamoDbVersionAttribute` anotasi.

### Menerapkan penghitung dengan `AtomicCounterExtension`
<a name="ddb-en-client-extensions-ACE"></a>

`AtomicCounterExtension`Ekstensi menambah atribut numerik yang ditandai setiap kali catatan ditulis ke database. Anda dapat menentukan nilai awal dan kenaikan. Jika tidak ada nilai yang ditentukan, nilai awal diatur ke 0 dan nilai atribut meningkat sebesar 1.

#### Konfigurasi
<a name="ddb-en-client-extensions-ACE-conf"></a>

Untuk menentukan atribut mana yang merupakan penghitung, beri tag atribut tipe `Long` dalam skema tabel.

Cuplikan berikut menunjukkan penggunaan nilai awal dan kenaikan default untuk atribut. `counter`

```
    @DynamoDbAtomicCounter
    public Long getCounter() {...};
    public void setCounter(Long counter) {...};
```

Pendekatan skema tabel statis ditunjukkan dalam cuplikan berikut. Ekstensi penghitung atom menggunakan nilai awal 10 dan menambah nilai sebesar 5 setiap kali catatan ditulis.

```
    .addAttribute(Integer.class, a -> a.name("counter")
                                       .getter(Customer::getCounter)
                                       .setter(Customer::setCounter)
                                        // Apply the 'atomicCounter' tag to the attribute with start and increment values.
                                       .tags(StaticAttributeTags.atomicCounter(10L, 5L))
```

### Tambahkan stempel waktu dengan `AutoGeneratedTimestampRecordExtension`
<a name="ddb-en-client-extensions-AGTE"></a>

`AutoGeneratedTimestampRecordExtension`Ekstensi secara otomatis memperbarui atribut tipe yang ditandai `[Instant](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html)` dengan stempel waktu saat ini setiap kali item berhasil ditulis ke database. Ekstensi ini tidak dimuat secara default.

#### Konfigurasi
<a name="ddb-en-client-extensions-AGTE-conf"></a>

Untuk menentukan atribut mana yang akan diperbarui dengan stempel waktu saat ini, beri tag `Instant` atribut dalam skema tabel.

`lastUpdate`Atribut adalah target perilaku ekstensi dalam cuplikan berikut. Perhatikan persyaratan bahwa atribut harus berupa `Instant` tipe.

```
    @DynamoDbAutoGeneratedTimestampAttribute
    public Instant getLastUpdate() {...}
    public void setLastUpdate(Instant lastUpdate) {...}
```

Pendekatan skema tabel statis setara ditunjukkan dalam cuplikan berikut.

```
     .addAttribute(Instant.class, a -> a.name("lastUpdate")
                                        .getter(Customer::getLastUpdate)
                                        .setter(Customer::setLastUpdate)
                                        // Applying the 'autoGeneratedTimestamp' tag to the attribute.
                                        .tags(AutoGeneratedTimestampRecordExtension.AttributeTags.autoGeneratedTimestampAttribute())
```

### Hasilkan UUID dengan AutoGeneratedUuidExtension
<a name="ddb-en-client-extensions-AGUE"></a>

`AutoGeneratedUuidExtension`Ekstensi menghasilkan UUID unik (Universally Unique Identifier) untuk atribut ketika catatan baru ditulis ke database. Menggunakan metode Java JDK [UUID.randomUUId ()](https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html#randomUUID--) dan berlaku untuk atribut tipe. `java.lang.String` Ekstensi ini tidak dimuat secara default.

#### Konfigurasi
<a name="ddb-en-client-extensions-AGUE-conf"></a>

`uniqueId`Atribut adalah target perilaku ekstensi dalam cuplikan berikut.

```
    @AutoGeneratedUuidExtension
    public String getUniqueId() {...}
    public void setUniqueId(String uniqueId) {...}
```

Pendekatan skema tabel statis setara ditunjukkan dalam cuplikan berikut.

```
     .addAttribute(String.class, a -> a.name("uniqueId")
                                        .getter(Customer::getUniqueId)
                                        .setter(Customer::setUniqueId)
                                        // Applying the 'autoGeneratedUuid' tag to the attribute.
                                        .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute())
```

Jika Anda ingin ekstensi mengisi UUID hanya untuk `putItem` metode dan bukan untuk `updateItem` metode, tambahkan anotasi [perilaku pembaruan](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html) seperti yang ditunjukkan pada cuplikan berikut.

```
    @AutoGeneratedUuidExtension
    @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)
    public String getUniqueId() {...}
    public void setUniqueId(String uniqueId) {...}
```

Jika Anda menggunakan pendekatan skema tabel statis, gunakan kode setara berikut.

```
     .addAttribute(String.class, a -> a.name("uniqueId")
                                        .getter(Customer::getUniqueId)
                                        .setter(Customer::setUniqueId)
                                        // Applying the 'autoGeneratedUuid' tag to the attribute.
                                        .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute(),
                                              StaticAttributeTags.updateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS))
```

# Contoh ekstensi kustom
<a name="ddb-en-client-extensions-custom"></a>

Anda dapat membuat ekstensi khusus dengan mengimplementasikan `DynamoDbEnhancedClientExtension` antarmuka. Kelas ekstensi kustom berikut menunjukkan `beforeWrite()` metode yang menggunakan ekspresi pembaruan untuk mengatur `registrationDate` atribut jika item dalam database belum memilikinya.

```
public final class CustomExtension implements DynamoDbEnhancedClientExtension {

    // 1. In a custom extension, use an UpdateExpression to define what action to take before
    //    an item is updated.
    @Override
    public WriteModification beforeWrite(DynamoDbExtensionContext.BeforeWrite context) {
        if ( context.operationContext().tableName().equals("Customer")
                && context.operationName().equals(OperationName.UPDATE_ITEM)) {
            return WriteModification.builder()
                    .updateExpression(createUpdateExpression())
                    .build();
        }
        return WriteModification.builder().build();  // Return an "empty" WriteModification instance if the extension should not be applied.
                                                     // In this case, if the code is not updating an item on the Customer table.
    }

    private static UpdateExpression createUpdateExpression() {

        // 2. Use a SetAction, a subclass of UpdateAction, to provide the values in the update.
        SetAction setAction =
                SetAction.builder()
                        .path("registrationDate")
                        .value("if_not_exists(registrationDate, :regValue)")
                        .putExpressionValue(":regValue", AttributeValue.fromS(Instant.now().toString()))
                        .build();
        // 3. Build the UpdateExpression with one or more UpdateAction.
        return UpdateExpression.builder()
                .addAction(setAction)
                .build();
    }
}
```

# Gunakan DynamoDB Enhanced Client API secara asinkron
<a name="ddb-en-client-async"></a>

Jika aplikasi Anda memerlukan panggilan asinkron non-pemblokiran ke DynamoDB, Anda dapat menggunakan file. [DynamoDbEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html) Ini mirip dengan implementasi sinkron tetapi dengan perbedaan utama berikut:

1. Ketika Anda membangun`DynamoDbEnhancedAsyncClient`, Anda harus menyediakan versi asinkron dari klien standar,`DynamoDbAsyncClient`, seperti yang ditunjukkan dalam cuplikan berikut.

   ```
    DynamoDbEnhancedAsyncClient enhancedClient = 
        DynamoDbEnhancedAsyncClient.builder()
                                   .dynamoDbClient(dynamoDbAsyncClient)
                                   .build();
   ```

1. Metode yang mengembalikan objek data tunggal `CompletableFuture` mengembalikan hasil bukan hanya hasilnya. Aplikasi Anda kemudian dapat melakukan pekerjaan lain tanpa harus memblokir hasilnya. Cuplikan berikut menunjukkan metode `getItem()` asinkron. 

   ```
   CompletableFuture<Customer> result = customerDynamoDbTable.getItem(customer);
   // Perform other work here.
   return result.join();   // Now block and wait for the result.
   ```

1. Metode yang mengembalikan daftar hasil paginasi mengembalikan sebuah [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)alih-alih [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html)yang dikembalikan sinkron `DynamoDbEnhanceClient` untuk metode yang sama. Aplikasi Anda kemudian dapat berlangganan handler ke penerbit itu untuk menangani hasil secara asinkron tanpa harus memblokir.

   ```
   PagePublisher<Customer> results = customerDynamoDbTable.query(r -> r.queryConditional(keyEqualTo(k -> k.partitionValue("Smith"))));
   results.subscribe(myCustomerResultsProcessor);
   // Perform other work and let the processor handle the results asynchronously.
   ```

   Untuk contoh yang lebih lengkap tentang bekerja dengan`SdkPublisher API`, lihat [contoh di](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-scan-async) bagian yang membahas `scan()` metode asinkron dari panduan ini.

# Anotasi kelas data
<a name="ddb-en-client-anno-index"></a>

Tabel berikut mencantumkan anotasi yang dapat digunakan pada kelas data dan menyediakan tautan ke informasi dan contoh dalam panduan ini. Tabel diurutkan dalam urutan abjad menaik dengan nama anotasi.


**Anotasi kelas data yang digunakan dalam panduan ini**  

| Nama anotasi | Anotasi berlaku untuk 1 | Apa yang dilakukannya | Dimana itu ditampilkan dalam panduan ini | 
| --- | --- | --- | --- | 
| DynamoDbAtomicCounter | atribut 2 | Menambah atribut numerik yang ditandai setiap kali catatan ditulis ke database. | [Pengantar dan diskusi.](ddb-en-client-extensions.md#ddb-en-client-extensions-ACE) | 
| DynamoDbAttribute | atribut | Mendefinisikan atau mengganti nama properti kacang yang dipetakan ke atribut tabel DynamoDB. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbAutoGeneratedTimestampAttribute | atribut | Memperbarui atribut yang ditandai dengan stempel waktu saat ini setiap kali item berhasil ditulis ke database | [Pengantar dan diskusi](ddb-en-client-extensions.md#ddb-en-client-extensions-AGTE). | 
| DynamoDbAutoGeneratedUuid | atribut | Menghasilkan UUID unik (Universally Unique Identifier) untuk atribut ketika catatan baru ditulis ke database. | [Pengantar dan diskusi.](ddb-en-client-extensions.md#ddb-en-client-extensions-AGUE) | 
| DynamoDbBean | class | Menandai kelas data sebagai dapat dipetakan ke skema tabel. | Pertama gunakan pada [kelas Pelanggan](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) di bagian Memulai. Beberapa penggunaan muncul di seluruh panduan. | 
| DynamoDbConvertedBy | atribut | Mengaitkan kustom AttributeConverter dengan atribut beranotasi. | [Diskusi awal dan contoh.](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-single) | 
| DynamoDbFlatten | atribut | Meratakan semua atribut dari kelas data DynamoDB terpisah dan menambahkannya sebagai atribut tingkat atas ke catatan yang dibaca dan ditulis ke database.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnore | atribut |  Menghasilkan atribut yang tersisa tidak dipetakan.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnoreNulls | atribut | Mencegah menyimpan atribut null dari objek bersarang DynamoDb . | [Diskusi dan contoh.](ddb-en-client-adv-features-ignore-null.md) | 
| DynamoDbImmutable | class |  Menandai kelas data yang tidak dapat diubah sebagai dapat dipetakan ke skema tabel.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPartitionKey | atribut |  Menandai atribut sebagai kunci partisi primer (kunci hash) dari DynamoDb tabel.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPreserveEmptyObject | atribut |  Menentukan bahwa jika tidak ada data hadir untuk objek dipetakan ke atribut beranotasi, objek harus diinisialisasi dengan semua bidang null.  | [Diskusi dan contoh.](ddb-en-client-adv-features-empty.md) | 
| DynamoDbSecondaryPartitionKey | atribut |  Menandai atribut sebagai kunci partisi untuk indeks sekunder global.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSecondarySortKey | atribut |  Menandai atribut sebagai kunci pengurutan opsional untuk indeks sekunder global atau lokal.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSortKey | atribut |  Menandai atribut sebagai kunci sortir primer opsional (range key).  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/id_id/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbUpdateBehavior | atribut |  Menentukan perilaku ketika atribut ini diperbarui sebagai bagian dari operasi 'update' seperti UpdateItem.  | [Pendahuluan dan contoh.](ddb-en-client-adv-features-upd-behavior.md) | 
| DynamoDbVersionAttribute | atribut | Menambah nomor versi item. | [Pengantar dan diskusi.](ddb-en-client-extensions.md#ddb-en-client-extensions-VRE) | 

1 Anda dapat menerapkan anotasi tingkat atribut ke pengambil atau penyetel, tetapi tidak keduanya. Panduan ini menunjukkan anotasi tentang getter.

2 Istilah `property` ini biasanya digunakan untuk nilai yang dienkapsulasi dalam kelas data. JavaBean Namun, panduan ini menggunakan istilah `attribute` sebagai gantinya, agar konsisten dengan terminologi yang digunakan oleh DynamoDB.