

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Travaillez avec DynamoDB
<a name="examples-dynamodb"></a>

[DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) est un service de base de données NoSQL entièrement géré qui fournit des performances rapides et prévisibles ainsi qu'une évolutivité sans faille. Cette section explique comment utiliser DynamoDB à l'aide de la version 2.x. AWS SDK pour Java 

## Choisissez votre client DynamoDB
<a name="ddb-clients-overview"></a>

Le SDK propose deux approches principales pour travailler avec DynamoDB :

Client de bas niveau (`DynamoDbClient`)  
Fournit un accès direct aux opérations DynamoDB avec un contrôle total sur les demandes et les réponses. Utilisez ce client lorsque vous avez besoin d'un contrôle précis ou lorsque vous travaillez avec des schémas dynamiques.

Client amélioré (`DynamoDbEnhancedClient`)  
Propose une programmation orientée objet avec mappage automatique entre les objets Java et les éléments DynamoDB. Fournit également des fonctionnalités orientées document pour travailler avec des données de type JSON qui ne suivent pas un schéma fixe. Utilisez ce client lorsque vous travaillez avec des modèles de données bien définis ou des données de type document.

## Configuration des clients DynamoDB
<a name="ddb-configuration-setup"></a>

Avant d'utiliser DynamoDB, configurez votre client pour des performances et une fiabilité optimales.

### Comprendre le comportement des nouvelles tentatives de DynamoDB
<a name="ddb-retry-behavior"></a>

Les clients DynamoDB utilisent un nombre maximal de tentatives par défaut de 8, ce qui est supérieur à celui des autres clients. Service AWS Ce nombre de tentatives plus élevé permet de gérer la nature distribuée et les limites de capacité temporaires de DynamoDB. Pour plus d'informations sur les stratégies de nouvelle tentative, consultez[Configurez le comportement des nouvelles tentatives dans AWS SDK for Java 2.x](retry-strategy.md).

### Optimisez les performances avec des points de terminaison basés sur des comptes
<a name="ddb-account-based-endpoints-v2"></a>

DynamoDB [AWS propose des points de terminaison basés sur les comptes](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.SDKOverview.html#Programming.SDKs.endpoints) qui améliorent les performances en utilisant AWS votre identifiant de compte pour rationaliser le routage des demandes. 

Pour utiliser cette fonctionnalité, vous devez disposer de la version 2.28.4 ou supérieure du. AWS SDK for Java 2.x Vous pouvez trouver la dernière version dans le [dépôt central de Maven](https://central.sonatype.com/artifact/software.amazon.awssdk/bom/versions). Les versions du SDK prises en charge utilisent automatiquement les nouveaux points de terminaison.

Pour désactiver le routage basé sur le compte, choisissez l'une des options suivantes :
+ Configurez un client `AccountIdEndpointMode` de service DynamoDB défini sur. `DISABLED`
+ Définissez une variable d'environnement.
+ Définissez une propriété du système JVM.
+ Mettez à jour le paramètre du fichier de AWS configuration partagé.

L'exemple suivant montre comment désactiver le routage basé sur un compte en configurant un client de service DynamoDB :

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

Pour plus d'informations sur les autres options de configuration, consultez la section [Points de terminaison basés sur un compte](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html) dans le guide de référence des outils AWS SDKs et.

## Ce qui est abordé dans cette rubrique
<a name="ddb-topics-overview"></a>

Les sections suivantes expliquent comment utiliser DynamoDB :
+ [Travaillez avec des tables dans DynamoDB](examples-dynamodb-tables.md)- Créer, décrire, mettre à jour et supprimer des tables
+ [Travaillez avec des objets dans DynamoDB](examples-dynamodb-items.md)- Ajouter, récupérer et mettre à jour des éléments individuels
+ [Mappez des objets Java à des éléments DynamoDB à l'aide du AWS SDK for Java 2.x](dynamodb-enhanced-client.md)- Utilisez le mappage d'objets et les données orientées document avec le client amélioré

Pour des exemples de code DynamoDB supplémentaires, consultez la section Exemples de code [DynamoDB dans la bibliothèque d'exemples](java_dynamodb_code_examples.md) de code. AWS 

# Travaillez avec des tables dans DynamoDB
<a name="examples-dynamodb-tables"></a>

Les tables sont les conteneurs de tous les éléments d'une DynamoDB base de données. Avant de pouvoir ajouter ou supprimer des données DynamoDB, vous devez créer une table.

Pour chaque table, vous devez définir :
+ *Nom* de table unique pour votre compte et votre région.
+ Une *clé primaire* pour laquelle chaque valeur doit être unique : deux éléments de votre table ne peuvent pas avoir la même valeur de clé primaire.

  Une clé primaire peut être *simple*, constituée d'une seule clé de partition (HASH) ou *composite*, constituée d'une partition et d'une clé de tri (RANGE).

  Chaque valeur clé est associée à un *type de données*, énuméré par la [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)classe. La valeur de la clé peut être binaire (B), numérique (N) ou de type chaîne (S). Pour plus d'informations, consultez la section [Règles de dénomination et types de données](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) dans le Guide du Amazon DynamoDB développeur.
+  Le *débit alloué* désigne les valeurs qui définissent le nombre d'unités de capacité en lecture/écriture réservées pour la table.
**Note**  
Amazon DynamoDB la [tarification](https://aws.amazon.com/dynamodb/pricing/) est basée sur les valeurs de débit provisionnées que vous définissez sur vos tables. Ne réservez donc que la capacité dont vous pensez avoir besoin pour votre table.

  Le débit alloué pour une table peut être modifié à tout moment pour que vous puissiez ajuster la capacité si vos besoins évoluent.

## Créer une table
<a name="dynamodb-create-table"></a>

Utilisez `DynamoDbClient’s` `createTable` cette méthode pour créer une nouvelle DynamoDB table. Vous devez créer des attributs de table et un schéma de table qui sont utilisés pour identifier la clé primaire de votre table. Vous devez également fournir des valeurs initiales de débit alloué et un nom de table.

**Note**  
Si une table portant le nom que vous avez choisi existe déjà, un `[DynamoDbException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/DynamoDbException.html)` est généré.

### Créer une table avec une clé primaire simple
<a name="dynamodb-create-table-simple"></a>

Ce code crée une table avec un attribut qui est la clé primaire simple de la table. L'exemple utilise `[AttributeDefinition](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeDefinition.html)` et `[KeySchemaElement](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/KeySchemaElement.html)` objecte pour. [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)

 **Importations** 

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

 **Code** 

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

Consultez l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTable.java) sur GitHub.

### Créer une table avec une clé primaire composite
<a name="dynamodb-create-table-composite"></a>

L'exemple suivant crée une table avec deux attributs. Les deux attributs sont utilisés pour la clé primaire composite.

 **Importations** 

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

 **Code** 

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

Consultez l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTableCompositeKey.java) sur GitHub.

## Répertorier des tables
<a name="dynamodb-list-tables"></a>

Vous pouvez répertorier les tables d'une région donnée en appelant la `DynamoDbClient’s` `listTables` méthode.

**Note**  
Si la table nommée n'existe pas pour votre compte et votre région, un [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)est généré.

 **Importations** 

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

 **Code** 

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

Par défaut, jusqu'à 100 tables sont renvoyées par appel. À utiliser `lastEvaluatedTableName` sur l'[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)objet renvoyé pour obtenir la dernière table évaluée. Vous pouvez utiliser cette valeur pour démarrer la liste après la dernière valeur renvoyée de la liste précédente.

Consultez l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/ListTables.java) sur GitHub.

## Décrire (obtenir des informations) sur une table
<a name="dynamodb-describe-table"></a>

Utilisez `DynamoDbClient’s` `describeTable` cette méthode pour obtenir des informations sur une table.

**Note**  
Si la table nommée n'existe pas pour votre compte et votre région, un [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)est généré.

 **Importations** 

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

 **Code** 

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

Consultez l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DescribeTable.java) sur GitHub.

## Modifier (mettre à jour) une table
<a name="dynamodb-update-table"></a>

Vous pouvez modifier les valeurs de débit provisionnées de votre table à tout moment en appelant la `DynamoDbClient’s` `updateTable` méthode.

**Note**  
Si la table nommée n'existe pas pour votre compte et votre région, un [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)est généré.

 **Importations** 

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

 **Code** 

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

Consultez l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateTable.java) sur GitHub.

## Supprimer une table
<a name="dynamodb-delete-table"></a>

Pour supprimer une table, appelez la `DynamoDbClient’s` `deleteTable` méthode et indiquez le nom de la table.

**Note**  
Si la table nommée n'existe pas pour votre compte et votre région, un [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)est généré.

 **Importations** 

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

 **Code** 

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

Consultez l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteTable.java) sur GitHub.

## En savoir plus
<a name="more-information"></a>
+  [Instructions relatives à l'utilisation des tables](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html) dans le guide du Amazon DynamoDB développeur
+  [Utilisation des tableaux DynamoDB dans](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html) le guide du Amazon DynamoDB développeur

# Travaillez avec des objets dans DynamoDB
<a name="examples-dynamodb-items"></a>

Dans DynamoDB, un élément est un ensemble d'*attributs*, chacun ayant un *nom* et une *valeur*. Une valeur d'attribut peut être de type scalar, set ou document. Pour plus d'informations, consultez la section [Règles de dénomination et types de données](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) dans le Guide du Amazon DynamoDB développeur.

## Extraction (get) d’un élément d'une table
<a name="dynamodb-get-item"></a>

Appelez la `getItem` méthode DynamoDbClient's et transmettez-lui un [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html)objet avec le nom de la table et la valeur de la clé primaire de l'élément souhaité. Elle renvoie un [GetItemResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemResponse.html)objet avec tous les attributs de cet élément. Vous pouvez spécifier une ou plusieurs [expressions de projection](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html) dans `GetItemRequest` pour extraire des attributs spécifiques.

Vous pouvez utiliser la `item()` méthode de l'`GetItemResponse`objet renvoyé pour récupérer une [carte](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) des paires clé (chaîne [AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html)) et valeur () associées à l'élément.

 **Importations** 

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

 **Code** 

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

Voir l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/GetItem.java) sur GitHub.

## Extraire (get) un élément d'une table à l'aide du client asynchrone
<a name="id1ddb"></a>

Invoquez la `getItem` méthode du DynamoDbAsyncClient et transmettez-lui un [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html)objet avec le nom de la table et la valeur de la clé primaire de l'élément souhaité.

Vous pouvez renvoyer une instance [Collection](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Collection.html) avec tous les attributs de cet élément (reportez-vous à l'exemple suivant).

 **Importations** 

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

 **Code** 

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

Voir l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/DynamoDBAsyncGetItem.java) sur GitHub.

## Ajouter un nouvel élément à une table
<a name="dynamodb-add-item"></a>

Créez un [mappage](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) des paires clé-valeur qui représentent les attributs de l'élément. Elles doivent inclure les valeurs des champs de clé primaire de la table. Si l'élément identifié par la clé primaire existe déjà, ses champs sont *mis à jour* par la demande.

**Note**  
Si la table nommée n'existe pas pour votre compte et votre région, un [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)est généré.

 **Importations** 

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

 **Code** 

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

Voir l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/PutItem.java) sur GitHub.

## Mettre à jour un élément existant dans une table
<a name="dynamodb-update-item"></a>

Vous pouvez mettre à jour un attribut pour un élément déjà existant dans une table à l'aide de la méthode `updateItem` d'DynamoDbClient, en fournissant un nom de table, une valeur de clé primaire et un mappage des champs à mettre à jour.

**Note**  
Si la table nommée n'existe pas pour votre compte et votre région, ou si l'élément identifié par la clé primaire que vous avez transmise n'existe pas, un [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)est généré.

 **Importations** 

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

 **Code** 

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

Voir l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateItem.java) sur GitHub.

## Supprimer un élément existant d’une table
<a name="dynamodb-delete-item"></a>

Vous pouvez supprimer un élément existant dans une table en utilisant la `deleteItem` méthode DynamoDbClient's et en fournissant un nom de table ainsi que la valeur de la clé primaire.

**Note**  
Si la table nommée n'existe pas pour votre compte et votre région, ou si l'élément identifié par la clé primaire que vous avez transmise n'existe pas, un [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)est généré.

 **Importations** 

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

 **Code** 

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

Voir l'[exemple complet](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteItem.java) sur GitHub.

## En savoir plus
<a name="more-information"></a>
+  [Directives relatives à l'utilisation des éléments](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/best-practices.html) du guide du Amazon DynamoDB développeur
+  [Utilisation des éléments contenus DynamoDB dans](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/WorkingWithItems.html) le guide du Amazon DynamoDB développeur

# Mappez des objets Java à des éléments DynamoDB à l'aide du AWS SDK for Java 2.x
<a name="dynamodb-enhanced-client"></a>

L'API [DynamoDB Enhanced Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html) est une bibliothèque de haut niveau qui succède à la classe `DynamoDBMapper` du SDK for Java v1.x. Il offre un moyen simple de mapper des classes côté client à des tables DynamoDB. Vous définissez les relations entre les tables et les classes de données correspondantes dans votre code. Après avoir défini ces relations, vous pouvez effectuer de manière intuitive diverses opérations de création, de lecture, de mise à jour ou de suppression (CRUD) sur des tables ou des éléments dans DynamoDB.

L'API DynamoDB Enhanced Client inclut également l'API [Enhanced Document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) qui vous permet de travailler avec des éléments de type document qui ne suivent pas un schéma défini. 

**Topics**
+ [Commencez à utiliser l'API client améliorée DynamoDB](ddb-en-client-getting-started.md)
+ [Découvrez les principes de base de l'API client améliorée DynamoDB](ddb-en-client-use.md)
+ [Utiliser les fonctionnalités de cartographie avancées](ddb-en-client-adv-features.md)
+ [Travaillez avec des documents JSON avec l'API de document améliorée pour DynamoDB](ddb-en-client-doc-api.md)
+ [Utiliser des extensions pour personnaliser les opérations du client DynamoDB Enhanced](ddb-en-client-extensions.md)
+ [Utiliser l'API client améliorée DynamoDB de manière asynchrone](ddb-en-client-async.md)
+ [Annotations de classes de données](ddb-en-client-anno-index.md)

# Commencez à utiliser l'API client améliorée DynamoDB
<a name="ddb-en-client-getting-started"></a>

Le didacticiel suivant présente les principes fondamentaux dont vous avez besoin pour utiliser l'API client améliorée DynamoDB.

## Ajouter des dépendances
<a name="ddb-en-client-gs-dep"></a>

Pour commencer à utiliser l'API client améliorée DynamoDB dans votre projet, ajoutez une dépendance à l'artefact Maven. `dynamodb-enhanced` Cela est illustré dans les exemples suivants. 

------
#### [ 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>
```

Effectuez une recherche dans le référentiel central Maven pour trouver la [dernière version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) et remplacez-la *<VERSION>* par cette valeur.

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

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

Effectuez une recherche dans le référentiel central Maven pour trouver la [dernière version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) et remplacez-la *<VERSION>* par cette valeur.

------

# Générer un `TableSchema` à partir d'une classe de données
<a name="ddb-en-client-gs-tableschema"></a>

A `[TableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableSchema.html)` permet au client amélioré de mapper les valeurs d'attribut DynamoDB vers et depuis vos classes côté client. Dans ce didacticiel, vous découvrirez `TableSchema` s dérivé d'une classe de données statique et généré à partir de code à l'aide d'un générateur.

## Utiliser une classe de données annotée
<a name="ddb-en-client-gs-tableschema-anno-bean"></a>

Le SDK pour Java 2.x inclut [un ensemble d'annotations que vous pouvez utiliser avec une classe de](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/package-summary.html) données pour générer `TableSchema` rapidement un fichier permettant de mapper vos classes à des tables.

Commencez par créer une classe de données conforme à la [JavaBean spécification](https://download.oracle.com/otn-pub/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/beans.101.pdf). La spécification exige qu'une classe ait un constructeur public sans argument et dispose de getters et setters pour chaque attribut de la classe. Incluez une annotation au niveau de la classe pour indiquer que la classe de données est une. `DynamoDbBean` Incluez également, au minimum, une `DynamoDbPartitionKey` annotation sur le getter ou le setter pour l'attribut clé primaire. 

Vous pouvez appliquer des [annotations au niveau des attributs](ddb-en-client-anno-index.md) aux getters ou aux setters, mais pas aux deux.

**Note**  
Le terme `property` est normalement utilisé pour une valeur encapsulée dans un JavaBean. Toutefois, ce guide utilise ce terme à la `attribute` place, par souci de cohérence avec la terminologie utilisée par DynamoDB.

La `Customer` classe suivante affiche les annotations qui lient la définition de classe à une table DynamoDB.

### classe `Customer`
<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 + "]";
    }
}
```

Après avoir créé une classe de données annotée, utilisez-la pour créer la`TableSchema`, comme indiqué dans l'extrait de code suivant.

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

A `TableSchema` est conçu pour être statique et immuable. Vous pouvez généralement l'instancier au moment du chargement de la classe.

La méthode static `TableSchema.fromBean()` factory introspecte le bean pour générer le mappage des attributs de classe de données (propriétés) vers et depuis les attributs DynamoDB.

Pour un exemple d'utilisation d'un modèle de données composé de plusieurs classes de données, consultez la `Person` classe dans la [Travaillez avec des attributs tels que des beans, des cartes, des listes et des ensembles](ddb-en-client-adv-features-nested.md) section.

## Utilisez un constructeur
<a name="ddb-en-client-gs-tableschema-builder"></a>

Vous pouvez éviter le coût de l'introspection des haricots si vous définissez le schéma de table dans le code. Si vous codez le schéma, votre classe n'a pas besoin de suivre les normes de JavaBean dénomination ni d'être annotée. L'exemple suivant utilise un générateur et est équivalent à l'exemple de `Customer` classe qui utilise des annotations.

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

# Créez un client amélioré et `DynamoDbTable`
<a name="ddb-en-client-getting-started-dynamodbTable"></a>

## Créez un client amélioré
<a name="ddb-en-client-getting-started-dynamodbTable-eclient"></a>

La [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html)classe, ou son équivalent asynchrone [DynamoDbEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html), est le point d'entrée pour utiliser l'API DynamoDB Enhanced Client.

Le client amélioré a besoin d'une norme `[DynamoDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html)` pour effectuer le travail. L'API propose deux méthodes pour créer une `DynamoDbEnhancedClient` instance. La première option, illustrée dans l'extrait suivant, crée une norme dont les paramètres `DynamoDbClient` par défaut sont extraits des paramètres de configuration.

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

Si vous souhaitez configurer le client standard sous-jacent, vous pouvez le fournir à la méthode de création du client amélioré, comme indiqué dans l'extrait suivant.

```
// 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();
```

## Créer une instance `DynamoDbTable`
<a name="ddb-en-client-getting-started-dynamodbTable-table"></a>

Considérez 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)comme la représentation côté client d'une table DynamoDB qui utilise la fonctionnalité de mappage fournie par a. `TableSchema` La `DynamoDbTable` classe fournit des méthodes pour les opérations CRUD qui vous permettent d'interagir avec une seule table DynamoDB.

`DynamoDbTable<T>`est une classe générique qui prend un seul argument de type, qu'il s'agisse d'une classe personnalisée ou d'un `EnhancedDocument` lorsque vous travaillez avec des éléments de type document. Ce type d'argument établit la relation entre la classe que vous utilisez et l'unique table DynamoDB.

Utilisez la méthode `table()` factory du `DynamoDbEnhancedClient` pour créer une `DynamoDbTable` instance, comme indiqué dans l'extrait de code suivant.

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

`DynamoDbTable`les instances sont candidates aux singletons car elles sont immuables et peuvent être utilisées dans l'ensemble de votre application.

Votre code possède désormais une représentation en mémoire d'une table DynamoDB qui peut fonctionner avec des instances. `Customer` La table DynamoDB réelle peut exister ou ne pas exister. Si la table nommée existe `Customer` déjà, vous pouvez commencer à effectuer des opérations CRUD sur elle. Si elle n'existe pas, utilisez l'`DynamoDbTable`instance pour créer la table comme indiqué dans la section suivante.

# Créez une table DynamoDB si nécessaire
<a name="ddb-en-client-gs-ddbtable"></a>

Après avoir créé une `DynamoDbTable` instance, utilisez-la pour créer une *seule fois* une table dans DynamoDB.

## Créer un exemple de code de table
<a name="ddb-en-client-gs-ddbtable-createex"></a>

L'exemple suivant crée une table DynamoDB basée sur `Customer` la classe de données. 

Cet exemple crée une table DynamoDB dont le nom est identique au `Customer` nom de classe, mais le nom de la table peut être différent. Quel que soit le nom que vous donnez à la table, vous devez utiliser ce nom dans d'autres applications pour travailler avec la table. Fournissez ce nom à la `table()` méthode chaque fois que vous créez un autre `DynamoDbTable` objet afin de travailler avec la table DynamoDB sous-jacente.

Le paramètre Java lambda,`builder`, transmis à la `createTable` méthode vous permet de [personnaliser le tableau](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html). Dans cet exemple, le [débit provisionné](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.ProvisionedThroughput.Manual) est configuré. Si vous souhaitez utiliser les paramètres par défaut lorsque vous créez une table, ignorez le générateur, comme indiqué dans l'extrait de code suivant.

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

Lorsque les paramètres par défaut sont utilisés, les valeurs du débit provisionné ne sont pas définies. Au lieu de cela, le mode de facturation de la table est défini [sur demande](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.OnDemand).

L'exemple utilise également un `[DynamoDbWaiter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/waiters/DynamoDbWaiter.html)` avant de tenter d'imprimer le nom de la table reçu dans la réponse. La création d'une table prend un certain temps. Par conséquent, l'utilisation d'un serveur signifie que vous n'avez pas à écrire une logique qui interroge le service DynamoDB pour vérifier si la table existe avant de l'utiliser.

### Importations
<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;
```

### Code
<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.");
     }
 }
```

**Note**  
Les noms d'attributs d'une table DynamoDB commencent par une lettre minuscule lorsque la table est générée à partir d'une classe de données. Si vous souhaitez que le nom d'attribut de la table commence par une lettre majuscule, utilisez l'[`@DynamoDbAttribute(NAME)`annotation](ddb-en-client-adv-features-inex-attr.md) et indiquez le nom souhaité en tant que paramètre.

# Réaliser des opérations
<a name="ddb-en-client-gs-use"></a>

Une fois la table créée, utilisez l'`DynamoDbTable`instance pour effectuer des opérations sur la table DynamoDB. 

Dans l'exemple suivant, un singleton `DynamoDbTable<Customer>` est transmis en tant que paramètre avec une instance de [classe de `Customer` données](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) pour ajouter un nouvel élément à la table.

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

## Objet `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"));
```

Avant d'envoyer l'`customer`objet au service DynamoDB, enregistrez le résultat de la méthode de l'objet `toString()` pour le comparer à ce que le client amélioré envoie.

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

La journalisation au niveau du fil indique la charge utile de la demande générée. Le client amélioré a généré la représentation de bas niveau à partir de la classe de données. L'`regDate`attribut, qui est un `Instant` type en Java, est représenté sous la forme d'une chaîne DynamoDB.

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

# Travailler avec une table existante
<a name="ddb-en-client-gs-existingtable"></a>

La section précédente a montré comment créer une table DynamoDB à partir d'une classe de données Java. Si vous possédez déjà une table et que vous souhaitez utiliser les fonctionnalités du client amélioré, vous pouvez créer une classe de données Java qui fonctionnera avec la table. Vous devez examiner la table DynamoDB et ajouter les annotations nécessaires à la classe de données. 

Avant de travailler avec une table existante, appelez la `DynamoDbEnhanced.table()` méthode. Cela a été fait dans l'exemple précédent avec l'instruction suivante.

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

Une fois l'`DynamoDbTable`instance renvoyée, vous pouvez commencer à travailler immédiatement avec la table sous-jacente. Il n'est pas nécessaire de recréer la table en appelant la `DynamoDbTable.createTable()` méthode.

L'exemple suivant illustre cela en récupérant immédiatement une `Customer` instance de la table 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());
```

**Important**  
Le nom de table utilisé dans la `table()` méthode doit correspondre au nom de table DynamoDB existant.

# Découvrez les principes de base de l'API client améliorée DynamoDB
<a name="ddb-en-client-use"></a>

Cette rubrique décrit les fonctionnalités de base de l'API DynamoDB Enhanced Client et les compare à l'API client [DynamoDB standard](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html).

Si vous découvrez l'API DynamoDB Enhanced Client, nous vous recommandons de suivre [le didacticiel d'introduction pour vous familiariser avec les](ddb-en-client-getting-started.md) classes fondamentales.

## Éléments DynamoDB en Java
<a name="ddb-en-client-use-usecase"></a>

Les tables DynamoDB stockent des éléments. Selon votre cas d'utilisation, les éléments du côté Java peuvent prendre la forme de données structurées statiquement ou de structures créées dynamiquement. 

Si votre cas d'utilisation nécessite des éléments dotés d'un ensemble cohérent d'attributs, utilisez des [classes annotées](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean) ou utilisez un [générateur](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-builder) pour générer le type statique `TableSchema` approprié. 

Sinon, si vous devez stocker des éléments composés de différentes structures, créez un`DocumentTableSchema`. `DocumentTableSchema`fait partie de l'[API Enhanced Document](ddb-en-client-doc-api.md) et ne nécessite qu'une clé primaire de type statique et fonctionne avec des `EnhancedDocument` instances pour contenir les éléments de données. L'API de document améliorée est abordée dans une autre [rubrique.](ddb-en-client-doc-api.md)

## Types d'attributs pour les classes de modèles de données
<a name="ddb-en-client-use-types"></a>

Bien que DynamoDB prenne [en charge un petit nombre de types d'attributs](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) par rapport au système de types riches de Java, l'API DynamoDB Enhanced Client fournit des mécanismes permettant de convertir les membres d'une classe Java vers et depuis les types d'attributs DynamoDB.

Les types d'attributs (propriétés) de vos classes de données Java doivent être des types d'objets et non des primitives. Par exemple, utilisez toujours des types de données `Long` et des `Integer` objets, `long` et non des `int` primitives.

[Par défaut, l'API DynamoDB Enhanced Client prend en charge les convertisseurs d'attributs pour un grand nombre de types, [tels que](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html) Integer [[BigDecimal](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/BigDecimalAttributeConverter.html), String et](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) Instant.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/InstantAsStringAttributeConverter.html) La liste apparaît dans les [classes d'implémentation connues de l' AttributeConverter interface](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html). La liste comprend de nombreux types et collections tels que des cartes, des listes et des ensembles.

Pour stocker les données d'un type d'attribut qui n'est pas pris en charge par défaut ou qui n'est pas conforme à la JavaBean convention, vous pouvez écrire une `AttributeConverter` implémentation personnalisée pour effectuer la conversion. Consultez la section sur la conversion d'attributs pour un [exemple](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example).

Pour stocker les données d'un type d'attribut dont la classe est conforme à la spécification Java Beans (ou d'une [classe de données immuable](ddb-en-client-use-immut.md)), vous pouvez adopter deux approches. 
+ Si vous avez accès au fichier source, vous pouvez annoter la classe avec `@DynamoDbBean` (ou`@DynamoDbImmutable`). La section qui traite des attributs imbriqués présente des [exemples](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-anno) d'utilisation de classes annotées.
+ Si vous n'avez pas accès au fichier source de la classe de JavaBean données pour l'attribut (ou si vous ne souhaitez pas annoter le fichier source d'une classe à laquelle vous avez accès), vous pouvez utiliser l'approche du générateur. Cela crée un schéma de table sans définir les clés. Vous pouvez ensuite imbriquer ce schéma de table dans un autre schéma de table pour effectuer le mappage. La section des attributs imbriqués contient un [exemple](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-builder) illustrant l'utilisation de schémas imbriqués.

### Valeurs nulles
<a name="ddb-en-client-use-types-nulls"></a>

Lorsque vous utilisez `putItem` cette méthode, le client amélioré n'inclut pas les attributs à valeur nulle d'un objet de données mappé dans la demande adressée à DynamoDB.

Le comportement par défaut du SDK pour les `updateItem` demandes supprime les attributs de l'élément de DynamoDB qui sont définis sur null dans l'objet que vous soumettez dans la méthode. `updateItem` Si vous avez l'intention de mettre à jour certaines valeurs d'attributs et de conserver les autres inchangées, deux options s'offrent à vous.
+ Récupérez l'élément (en utilisant`getItem`) avant de modifier les valeurs. En utilisant cette approche, le SDK soumet toutes les valeurs anciennes et mises à jour à DynamoDB.
+ Utilisez le `[IgnoreNullsMode](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html).SCALAR_ONLY` ou `IgnoreNullsMode.MAPS_ONLY` lorsque vous créez la demande pour mettre à jour l'élément. Les deux modes ignorent les propriétés à valeur nulle de l'objet qui représentent des attributs scalaires dans DynamoDB. La [Mettre à jour les éléments contenant des types complexes](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-updates) rubrique de ce guide contient plus d'informations sur les `IgnoreNullsMode` valeurs et sur la manière de travailler avec des types complexes.

L'exemple suivant illustre `ignoreNullsMode()` la `updateItem()` méthode.

```
    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]
```

## Méthodes de base du client DynamoDB Enhanced
<a name="ddb-en-client-use-basic-ops"></a>

Les méthodes de base du client amélioré correspondent aux opérations de service DynamoDB dont elles portent le nom. Les exemples suivants montrent la variante la plus simple de chaque méthode. Vous pouvez personnaliser chaque méthode en transmettant un objet de demande amélioré. Les objets de requête améliorés offrent la plupart des fonctionnalités disponibles dans le client DynamoDB standard. Ils sont entièrement documentés dans le Guide de référence des AWS SDK for Java 2.x API.

L'exemple utilise ce qui [classe `Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) est indiqué précédemment.

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

## Comparez le client DynamoDB amélioré au client DynamoDB standard
<a name="ddb-en-client-use-compare"></a>

Les APIs clients DynamoDB (standard [et](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html) amélioré) vous [permettent](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html) de travailler avec des tables DynamoDB pour effectuer des opérations CRUD (création, lecture, mise à jour et suppression) au niveau des données. La différence entre le client APIs réside dans la manière dont cela est accompli. Avec le client standard, vous travaillez directement avec des attributs de données de bas niveau. L'API client améliorée utilise des classes Java familières et correspond à l'API de bas niveau utilisée en arrière-plan.

Bien que les deux clients APIs prennent en charge les opérations au niveau des données, le client DynamoDB standard prend également en charge les opérations au niveau des ressources. Les opérations au niveau des ressources gèrent la base de données, telles que la création de sauvegardes, la liste des tables et la mise à jour des tables. L'API client améliorée prend en charge un certain nombre d'opérations au niveau des ressources, telles que la création, la description et la suppression de tables.

Pour illustrer les différentes approches utilisées par les deux clients APIs, les exemples de code suivants montrent la création de la même `ProductCatalog` table à l'aide du client standard et du client amélioré.

### Comparaison : création d'une table à l'aide du client DynamoDB standard
<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))
);
```

### Comparaison : création d'une table à l'aide du client DynamoDB Enhanced
<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))
        )
);
```

Le client amélioré utilise la classe de données annotée suivante. Le client DynamoDB Enhanced fait correspondre les types de données Java aux types de données DynamoDB pour un code moins détaillé et plus facile à suivre. `ProductCatalog`est un exemple d'utilisation d'une classe immuable avec le client DynamoDB Enhanced. L'utilisation de classes immuables pour les classes de données mappées est [abordée plus loin](ddb-en-client-use-immut.md) dans cette rubrique.

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

Les deux exemples de code suivants illustrant une écriture par lots illustrent le caractère verbeux et le manque de sécurité de type liés à l'utilisation du client standard par opposition au client amélioré.

### Comparaison : écriture par lots à l'aide du client DynamoDB standard
<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());
    }
```

### Comparaison : écriture par lots à l'aide du client DynamoDB Enhanced
<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());
    }
```

# Travaillez avec des classes de données immuables
<a name="ddb-en-client-use-immut"></a>

La fonctionnalité de mappage de l'API DynamoDB Enhanced Client fonctionne avec des classes de données immuables. Une classe immuable ne possède que des méthodes getter et nécessite une classe de générateur que le kit SDK utilise pour créer des instances de la classe. Au lieu d'utiliser l'`@DynamoDbBean`annotation comme indiqué dans la [classe Customer](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust), les classes immuables utilisent l'`@DynamoDbImmutable`annotation, qui prend un paramètre indiquant la classe de générateur à utiliser.

La classe suivante est une version immuable de. `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); }
    }
}
```

Vous devez satisfaire aux exigences suivantes lorsque vous annotez une classe de données avec`@DynamoDbImmutable`.

1. Chaque méthode qui n'est pas une substitution `Object.class` et qui n'a pas été annotée `@DynamoDbIgnore` doit être un getter pour un attribut de la table DynamoDB.

1. Chaque getter doit avoir un setter correspondant distinguant majuscules et minuscules dans la classe de générateur.

1. Seule l'une des conditions de construction suivantes doit être respectée.
   + La classe de générateur doit avoir un constructeur public par défaut.
   + La classe de données doit avoir une méthode statique publique nommée `builder()` qui ne prend aucun paramètre et renvoie une instance de la classe de générateur. Cette option est affichée dans la `Customer` classe immuable.

1.  La classe builder doit avoir une méthode publique nommée `build()` qui ne prend aucun paramètre et renvoie une instance de la classe immuable. 

Pour créer un `TableSchema` pour votre classe immuable, utilisez la `fromImmutableClass()` méthode on `TableSchema` comme indiqué dans l'extrait suivant.

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

Tout comme vous pouvez créer une table DynamoDB à partir d'une classe mutable, vous pouvez en créer une à partir d'une classe immuable avec *un* appel unique à of, comme indiqué dans l'exemple `DynamoDbTable` d'`createTable()`extrait de code suivant.

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

## Utilisez des bibliothèques tierces, telles que Lombok
<a name="ddb-en-client-use-immut-lombok"></a>

Les bibliothèques tierces, telles que [Project Lombok](https://projectlombok.org/), aident à générer du code standard associé à des objets immuables. L'API DynamoDB Enhanced Client fonctionne avec ces bibliothèques tant que les classes de données respectent les conventions détaillées dans cette section. 

L'exemple suivant montre la `CustomerImmutable` classe immuable avec les annotations Lombok. Notez comment la `onMethod` fonctionnalité de Lombok copie les annotations DynamoDB basées sur les attributs, telles que, sur le code généré. `@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;
}
```

# Expressions et conditions d'utilisation
<a name="ddb-en-client-expressions"></a>

[Les expressions de l'API DynamoDB Enhanced Client sont des représentations Java des expressions DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html)

L'API client améliorée DynamoDB utilise trois types d'expressions :

[Expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)  
La `Expression` classe est utilisée lorsque vous définissez des conditions et des filtres.

[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)  
Ce type d'expression représente [les conditions clés](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions) pour les opérations de requête.

[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)  
Cette classe vous aide à écrire des expressions de [mise à jour DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html) et est actuellement utilisée dans le framework d'extension lorsque vous mettez à jour un élément.

## Anatomie de l'expression
<a name="ddb-en-client-expressions-compoonents"></a>

Une expression est composée des éléments suivants :
+ Une expression sous forme de chaîne (obligatoire). La chaîne contient une expression logique DynamoDB avec des noms d'espaces réservés pour les noms d'attributs et les valeurs d'attribut.
+ Une carte des valeurs d'expression (généralement obligatoire).
+ Carte des noms d'expressions (facultatif).

Utilisez un générateur pour générer un `Expression` objet qui prend la forme générale suivante.

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

`Expression`s nécessitent généralement une carte des valeurs d'expression. La carte fournit les valeurs des espaces réservés dans l'expression sous forme de chaîne. La clé de carte se compose du nom de l'espace réservé précédé de deux points (`:`) et la valeur de la carte est une instance de [AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html). La [AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/AttributeValues.html)classe dispose de méthodes pratiques pour générer une `AttributeValue` instance à partir d'un littéral. Vous pouvez également utiliser le `AttributeValue.Builder` pour générer une `AttributeValue` instance.

L'extrait suivant montre une carte avec deux entrées après la ligne de commentaire 2. La chaîne transmise à la `expression()` méthode, affichée après la ligne de commentaire 1, contient les espaces réservés que DynamoDB résout avant d'effectuer l'opération. Cet extrait ne contient pas de carte des noms d'expressions, car le *prix* est un nom d'attribut autorisé.

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

Si un nom d'attribut dans la table DynamoDB est un mot réservé, commence par un chiffre ou contient un espace, une carte des noms d'expressions est requise pour le. `Expression`

Par exemple, si le nom de l'attribut ne figurait `1price` pas `price` dans l'exemple de code précédent, celui-ci devra être modifié comme indiqué dans l'exemple suivant.

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

Un espace réservé pour le nom d'une expression commence par le signe dièse (`#`). Une entrée pour la carte des noms d'expressions utilise l'espace réservé comme clé et le nom de l'attribut comme valeur. La carte est ajoutée au générateur d'expressions avec la `expressionNames()` méthode. DynamoDB résout le nom de l'attribut avant d'effectuer l'opération.

Les valeurs d'expression ne sont pas obligatoires si une fonction est utilisée dans l'expression sous forme de chaîne. Voici un exemple de fonction d'expression`attribute_exists(<attribute_name>)`.

L'exemple suivant crée un fichier `Expression` qui utilise une fonction [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions). Dans cet exemple, la chaîne d'expression n'utilise aucun espace réservé. Cette expression peut être utilisée lors d'une `putItem` opération visant à vérifier si un élément existe déjà dans la base de données avec une valeur d'`movie`attribut égale à celle de l'`movie`attribut de l'objet de données.

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

Le guide du développeur DynamoDB contient des informations complètes sur les expressions de [bas niveau utilisées](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html) avec DynamoDB.

## Expressions de conditions et conditions
<a name="ddb-en-client-expressions-cond"></a>

Lorsque vous utilisez les `deleteItem()` méthodes`putItem()`, et`updateItem()`, ainsi que lorsque vous utilisez des opérations de transaction et de traitement par lots, vous utilisez `[Expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)` des objets pour spécifier les conditions que DynamoDB doit respecter pour poursuivre l'opération. Ces expressions sont appelées expressions de condition. Pour un exemple, consultez l'expression de condition utilisée dans la `addDeleteItem()` méthode (après la ligne de commentaire 1) de l'[exemple de transaction](ddb-en-client-use-multiop-trans.md#ddb-en-client-use-multiop-trans-writeitems-opcondition) présenté dans ce guide.

Lorsque vous utilisez les `query()` méthodes, une condition est exprimée sous la forme d'un [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). La `QueryConditional` classe dispose de plusieurs méthodes pratiques statiques qui vous aident à écrire les critères qui déterminent les éléments à lire dans DynamoDB.

Pour des exemples`QueryConditionals`, consultez le premier exemple de code de la [`Query`exemples de méthodes](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-query-example) section de ce guide.

## Expressions de filtrage
<a name="ddb-en-client-expressions-filter"></a>

Les expressions de filtre sont utilisées dans les opérations de numérisation et de requête pour filtrer les éléments renvoyés. 

Une expression de filtre est appliquée une fois que toutes les données ont été lues dans la base de données. Le coût de lecture est donc le même que s'il n'y avait pas de filtre. [Le guide du *développeur Amazon DynamoDB* contient plus d'informations sur l'utilisation d'expressions de filtre pour [les opérations de requête et](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.FilterExpression) de numérisation.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html#Scan.FilterExpression)

L'exemple suivant montre une expression de filtre ajoutée à une demande d'analyse. Les critères limitent les articles retournés aux articles dont le prix se situe entre 8,00 et 80,00€ inclus.

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

## Expressions de mise à jour
<a name="ddb-en-client-expressions-update"></a>

La méthode du client `updateItem()` DynamoDB Enhanced fournit une méthode standard pour mettre à jour des éléments dans DynamoDB. Toutefois, lorsque vous avez besoin de fonctionnalités supplémentaires, [UpdateExpressions](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html)fournissez une représentation sécurisée de la syntaxe de l'expression de mise à jour [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html). Par exemple, vous pouvez l'utiliser `UpdateExpressions` pour augmenter les valeurs sans lire au préalable les éléments de DynamoDB, ou pour ajouter des membres individuels à une liste. Les expressions de mise à jour sont actuellement disponibles dans les extensions personnalisées de la `updateItem()` méthode.

Pour un exemple utilisant des expressions de mise à jour, consultez l'[exemple d'extension personnalisée](ddb-en-client-extensions-custom.md) présenté dans ce guide.

De plus amples informations sur les expressions de mise à jour sont disponibles dans le [manuel du développeur Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html).

# Travailler avec des résultats paginés : scans et requêtes
<a name="ddb-en-client-use-multirecord"></a>

*Les `scan` `batch` méthodes `query` et de l'API DynamoDB Enhanced Client renvoient des réponses contenant une ou plusieurs pages.* Une page contient un ou plusieurs éléments. Votre code peut traiter la réponse page par page ou traiter des éléments individuels.

Une réponse paginée renvoyée par le `DynamoDbEnhancedClient` client synchrone renvoie un [PageIterable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PageIterable.html)objet, tandis qu'une réponse renvoyée par le client asynchrone `DynamoDbEnhancedAsyncClient` renvoie un objet. [PagePublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PagePublisher.html)

Cette section traite du traitement des résultats paginés et fournit des exemples d'utilisation du scan et de la requête APIs.

## Analyser une table
<a name="ddb-en-client-use-multirecord-scan"></a>

La [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))méthode du SDK correspond à l'opération [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) du même nom. L'API DynamoDB Enhanced Client propose les mêmes options, mais elle utilise un modèle d'objet familier et gère la pagination à votre place.

Tout d'abord, nous explorons l'`PageIterable`interface en examinant la `scan` méthode de la classe de mappage synchrone, [DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html).

### Utiliser l'API synchrone
<a name="ddb-en-client-use-multirecord-scan-sync"></a>

L'exemple suivant montre la `scan` méthode qui utilise une [expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html) pour filtrer les éléments renvoyés. [ProductCatalog](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)Il s'agit de l'objet modèle présenté précédemment.

L'expression de filtrage affichée après la ligne de commentaire 2 limite les `ProductCatalog` articles renvoyés à ceux dont le prix est compris entre 8,00 et 80,00€ inclusivement.

Cet exemple exclut également les `isbn` valeurs en utilisant la `attributesToProject` méthode indiquée après la ligne de commentaire 1.

Après la ligne de commentaire 3`pagedResults`, l'`PageIterable`objet est renvoyé par la `scan` méthode. La `stream` méthode de `PageIterable` renvoi d'un [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)objet, que vous pouvez utiliser pour traiter les pages. Dans cet exemple, le nombre de pages est compté et enregistré.

À partir de la ligne de commentaire 4, l'exemple montre deux variantes d'accès aux `ProductCatalog` éléments. La version située après la ligne de commentaire 4a parcourt chaque page et trie et enregistre les éléments de chaque page. La version située après la ligne de commentaire 4b ignore l'itération de la page et accède directement aux éléments.

L'`PageIterable`interface offre plusieurs manières de traiter les résultats grâce à ses deux interfaces parentes : [https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html)et [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`apporte les `forEach` `spliterator` méthodes, et `SdkIterable` apporte la `stream` méthode. `iterator`

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

### Utiliser l'API asynchrone
<a name="ddb-en-client-use-multirecord-scan-async"></a>

La `scan` méthode asynchrone renvoie les résultats sous forme d'`PagePublisher`objet. L'`PagePublisher`interface comporte deux `subscribe` méthodes que vous pouvez utiliser pour traiter les pages de réponse. L'une des `subscribe` méthodes provient de l'interface `org.reactivestreams.Publisher` parent. Pour traiter les pages à l'aide de cette première option, transmettez une `[Subscriber](https://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html)` instance à la `subscribe` méthode. Le premier exemple qui suit montre l'utilisation de la `subscribe` méthode.

La deuxième `subscribe` méthode provient de l'[SdkPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)interface. Cette version de `subscribe` accepte un [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)plutôt qu'un`Subscriber`. Cette variante de `subscribe` méthode est illustrée dans le deuxième exemple qui suit.

L'exemple suivant montre la version asynchrone de la `scan` méthode qui utilise la même expression de filtre que dans l'exemple précédent. 

Après la ligne de commentaire 3, `DynamoDbAsyncTable.scan` renvoie un `PagePublisher` objet. Sur la ligne suivante, le code crée une instance de l'`org.reactivestreams.Subscriber`interface`ProductCatalogSubscriber`, qui s'abonne à la ligne de commentaire 4 `PagePublisher` après.

L'`Subscriber`objet collecte les `ProductCatalog` éléments de chaque page de la `onNext` méthode après la ligne de commentaire 8 dans l'exemple `ProductCatalogSubscriber` de classe. Les éléments sont stockés dans la `List` variable privée et sont accessibles dans le code d'appel avec la `ProductCatalogSubscriber.getSubscribedItems()` méthode. Ceci est appelé après la ligne de commentaire 5.

Une fois la liste récupérée, le code trie tous les `ProductCatalog` articles par prix et enregistre chaque article.

La `ProductCatalogSubscriber` classe [CountDownLatch](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)in bloque le fil d'appel jusqu'à ce que tous les éléments aient été ajoutés à la liste avant de continuer après la ligne de commentaire 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;
        }
    }
```

L'exemple d'extrait de code suivant utilise la version de la `PagePublisher.subscribe` méthode qui accepte une ligne de commentaire `Consumer` 6 après. Le paramètre Java lambda consomme des pages, qui traitent ensuite chaque élément. Dans cet exemple, chaque page est traitée et les éléments de chaque page sont triés puis enregistrés.

```
        // 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.
```

La `items` méthode qui consiste à `PagePublisher` déballer les instances du modèle afin que votre code puisse traiter les éléments directement. Cette approche est illustrée dans l'extrait suivant.

```
        // 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.
```

## Interroger une table
<a name="ddb-en-client-use-multirecord-query"></a>

Vous pouvez utiliser le client DynamoDB amélioré pour interroger votre table et récupérer plusieurs éléments répondant à des critères spécifiques. La [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))méthode recherche des éléments en fonction des valeurs de clé primaire à l'`@DynamoDbPartitionKey`aide `@DynamoDbSortKey` des annotations facultatives définies dans votre classe de données.

La `query()` méthode nécessite une valeur de clé de partition et accepte éventuellement les conditions de clé de tri pour affiner davantage les résultats. Comme l'`scan`API, les requêtes renvoient a `PageIterable` pour les appels synchrones et a `PagePublisher` pour les appels asynchrones.

### `Query`exemples de méthodes
<a name="ddb-en-client-use-multirecord-query-example"></a>

L'exemple de code de `query()` méthode qui suit utilise la `MovieActor` classe. La classe de données définit une clé primaire composite composée de l'**`movie`**attribut en tant que clé de partition et de l'**`actor`**attribut en tant que clé de tri. 

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

Les exemples de code qui suivent portent sur les éléments suivants.

#### Éléments du `MovieActor` tableau
<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'}
```

Le code suivant définit deux `QueryConditional` instances : `keyEqual` (après la ligne de commentaire 1) et `sortGreaterThanOrEqualTo` (après la ligne de commentaire 1a).

#### Éléments de requête par clé de partition
<a name="keyEqual-query-conditional-example"></a>

L'`keyEqual`instance fait correspondre les éléments dont la valeur de clé de partition est de **`movie01`**. 

Cet exemple définit également une expression de filtre après la ligne de commentaire 2 qui filtre tout élément dépourvu de **`actingschoolname`**valeur.

`QueryEnhancedRequest`Combine la condition clé et l'expression du filtre pour la requête.

```
    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 — Sortie utilisant la `keyEqual` requête conditionnelle**  
Voici le résultat de l'exécution de la méthode. La sortie affiche les éléments dont `movieName` la valeur est **movie01** et n'affiche aucun élément dont la valeur est `actingSchoolName` égale à. **`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'}
```

#### Rechercher des éléments par clé de partition et clé de tri
<a name="sort-type-query-conditional-example"></a>

`sortGreaterThanOrEqualTo``QueryConditional`**Affine une correspondance de clé de partition (**movie01**) en ajoutant une condition de clé de tri pour les valeurs supérieures ou égales à actor2.**

[`QueryConditional`les méthodes](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) qui commencent par `sort` nécessitent qu'une valeur de clé de partition corresponde et affinent davantage la requête par une comparaison basée sur la valeur de la clé de tri. `Sort`dans le nom de la méthode ne signifie pas que les résultats sont triés, mais qu'une valeur de clé de tri sera utilisée pour la comparaison.

Dans l'extrait suivant, nous modifions la demande de requête affichée précédemment après la ligne de commentaire 3. Cet extrait remplace la requête conditionnelle « KeyEqual » par la requête conditionnelle « sortGreaterThan OrEqualTo » définie après la ligne de commentaire 1a. Le code suivant supprime également l'expression du filtre.

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

**Example — Sortie utilisant la `sortGreaterThanOrEqualTo` requête conditionnelle**  
La sortie suivante affiche les résultats de la requête. **La requête renvoie les éléments dont `movieName` la valeur est égale à **movie01** et uniquement les éléments dont `actorName` la valeur est supérieure ou égale à actor2.** Comme nous supprimons le filtre, la requête renvoie des éléments qui n'ont aucune valeur pour l'`actingSchoolName`attribut.  

```
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'}
```

# Effectuer des opérations par lots
<a name="ddb-en-client-use-multiop-batch"></a>

[L'API DynamoDB Enhanced Client propose deux méthodes par lots [`batchGetItem`, () et (](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))

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

Avec [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))cette méthode, vous pouvez récupérer jusqu'à 100 éléments individuels dans plusieurs tables dans une seule demande globale. L'exemple suivant utilise les classes de [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)données [`Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust)et présentées précédemment.

Dans l'exemple qui suit les lignes 1 et 2, vous créez `[ReadBatch](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ReadBatch.html)` des objets que vous ajoutez ultérieurement en tant que paramètres à la `batchGetItem()` méthode après la ligne de commentaire 3. 

Le code situé après la ligne de commentaire 1 crée le lot à lire dans le `Customer` tableau. Le code situé après la ligne de commentaire 1a montre l'utilisation d'un `[GetItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/GetItemEnhancedRequest.Builder.html)` générateur qui prend une valeur de clé primaire et une valeur de clé de tri pour spécifier l'élément à lire. Si la classe de données possède une clé composite, vous devez fournir à la fois la valeur de la clé de partition et la valeur de la clé de tri. 

Contrairement à la spécification de valeurs clés pour demander un élément, vous pouvez utiliser une classe de données pour demander un élément, comme indiqué après la ligne de commentaire 1b. Le SDK extrait les valeurs clés en arrière-plan avant de soumettre la demande.

[Lorsque vous spécifiez l'élément à l'aide de l'approche basée sur les clés, comme indiqué dans les deux instructions situées après 2a, vous pouvez également spécifier que DynamoDB doit effectuer une lecture très cohérente.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html) Lorsque la `consistentRead()` méthode est utilisée, elle doit être utilisée sur tous les éléments demandés pour la même table.

Pour récupérer les éléments trouvés par DynamoDB, utilisez `[resultsForTable() ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#resultsForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` la méthode indiquée après la ligne de commentaire 4. Appelez la méthode pour chaque table lue dans la demande. `resultsForTable()`renvoie une liste des éléments trouvés que vous pouvez traiter à l'aide de n'importe quelle `java.util.List` méthode. Cet exemple enregistre chaque élément.

Pour découvrir les éléments que DynamoDB n'a pas traités, utilisez l'approche indiquée après la ligne de commentaire 5. La `BatchGetResultPage` classe possède la `[unprocessedKeysForTable()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#unprocessedKeysForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` méthode qui vous donne accès à chaque clé non traitée. La [référence de l'BatchGetItem API](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html) contient plus d'informations sur les situations qui se traduisent par des éléments non traités.

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

Supposons que les éléments suivants se trouvent dans les deux tables avant d'exécuter l'exemple de code.

### Éléments figurant dans les tableaux
<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'}
```

La sortie suivante montre les éléments renvoyés et enregistrés après la ligne de commentaire 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'}
```

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

Le `batchWriteItem()` procédé place ou supprime plusieurs éléments dans une ou plusieurs tables. Vous pouvez spécifier jusqu'à 25 opérations de mise ou de suppression individuelles dans la demande. L'exemple suivant utilise les classes de [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)modèles [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)et présentées précédemment.

`WriteBatch`les objets sont créés après les lignes de commentaires 1 et 2. Pour le `ProductCatalog` tableau, le code place un élément et en supprime un. Pour le `MovieActor` tableau situé après la ligne de commentaire 2, le code place deux éléments et en supprime un.

La `batchWriteItem` méthode est appelée après la ligne de commentaire 3. Le `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteItemEnhancedRequest.Builder.html)` paramètre fournit les demandes par lots pour chaque table.

L'`[BatchWriteResult](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteResult.html)`objet renvoyé fournit des méthodes distinctes pour chaque opération afin de visualiser les demandes non traitées. Le code situé après la ligne de commentaire 4a fournit les clés pour les demandes de suppression non traitées et le code situé après la ligne de commentaire 4b fournit les éléments de saisie non traités.

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

Les méthodes d'assistance suivantes fournissent les objets modèles pour les opérations de saisie et de suppression.

### Méthodes auxiliaires
<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.     }
```

Supposons que les tables contiennent les éléments suivants avant d'exécuter l'exemple de code.

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

Une fois l'exemple de code terminé, les tableaux contiennent les éléments suivants.

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

Notez dans le `MovieActor` tableau que l'élément du `Blue Jasmine` film a été remplacé par l'élément utilisé dans la demande de vente acquise via la méthode d'`getMovieActorBlanchettPartial()`assistance. Si aucune valeur d'attribut Data Bean n'a été fournie, la valeur de la base de données est supprimée. C'est pourquoi le résultat `actingSchoolName` est nul pour l'élément `Blue Jasmine` vidéo.

**Note**  
[Bien que la documentation de l'API suggère que des expressions de condition peuvent être utilisées et que les mesures de capacité consommée et de collecte peuvent être renvoyées avec des demandes d'envoi et de [suppression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.html) individuelles, ce n'est pas le cas dans un scénario d'écriture par lots.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PutItemEnhancedRequest.html) Pour améliorer les performances des opérations par lots, ces options individuelles sont ignorées.

# Effectuer des opérations de transaction
<a name="ddb-en-client-use-multiop-trans"></a>

L'API DynamoDB Enhanced Client fournit `transactGetItems()` les méthodes et. `transactWriteItems()` Les méthodes de transaction du SDK for Java assurent l'atomicité, la cohérence, l'isolation et la durabilité (ACID) des tables DynamoDB, vous aidant ainsi à maintenir l'exactitude des données dans vos applications.

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

La `[transactGetItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactGetItems(java.util.function.Consumer))` méthode accepte jusqu'à 100 demandes individuelles d'articles. Tous les éléments sont lus en une seule transaction atomique. Le guide du *développeur Amazon DynamoDB* contient des informations sur les [conditions à l'origine de l'échec `transactGetItems()` d'une méthode, ainsi que sur le niveau d'isolation utilisé lorsque vous](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txgetitems) appelez. `[transactGetItem()](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-isolation)`

Après la ligne de commentaire 1 dans l'exemple suivant, le code appelle la `transactGetItems()` méthode avec un `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html)` paramètre. Le générateur `[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))` est invoqué trois fois avec un objet de données contenant les valeurs clés que le SDK utilisera pour générer la demande finale.

La demande renvoie une liste d'`[Document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html)`objets après la ligne de commentaire 2. La liste des documents renvoyée contient des instances de [document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html) non nulles contenant des données d'article dans le même ordre que celui demandé. La `[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))` méthode convertit un objet non typé en `Document` objet Java typé si des données d'élément ont été renvoyées, sinon la méthode renvoie 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());
        }
    }
```

Les tables DynamoDB contiennent les éléments suivants avant l'exécution de l'exemple de code.

```
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'}
```

La sortie suivante est enregistrée. Si un article est demandé mais introuvable, il n'est pas retourné comme c'est le cas pour la demande pour le film nommé`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'}
```

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

Il `[transactWriteItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))` accepte jusqu'à 100 actions de mise, de mise à jour ou de suppression dans une seule transaction atomique sur plusieurs tables. Le guide du *développeur Amazon DynamoDB* contient des informations détaillées sur les restrictions et les conditions de défaillance du fonctionnement du service [DynamoDB sous-jacent](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems).

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

Dans l'exemple suivant, quatre opérations sont demandées pour deux tables. Les classes [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)de modèles correspondantes [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)ont été présentées précédemment.

Chacune des trois opérations possibles (put, update et delete) utilise un paramètre de demande dédié pour spécifier les détails. 

Le code après la ligne de commentaire 1 montre la variante simple de la `addPutItem()` méthode. La méthode accepte un `[MappedTableResource](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/MappedTableResource.html)` objet et l'instance d'objet de données à placer. L'instruction située après la ligne de commentaire 2 indique la variante qui accepte une `[TransactPutItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactPutItemEnhancedRequest.html)` instance. Cette variante vous permet d'ajouter d'autres options dans la demande, comme une expression conditionnelle. L'[exemple](#ddb-en-client-use-multiop-trans-writeitems-opcondition) suivant montre une expression de condition pour une opération individuelle.

Une opération de mise à jour est demandée après la ligne de commentaire 3. `[TransactUpdateItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactUpdateItemEnhancedRequest.Builder.html)`possède une `ignoreNulls()` méthode qui vous permet de configurer ce que le SDK fait avec `null` les valeurs de l'objet modèle. Si la `ignoreNulls()` méthode renvoie true, le SDK ne supprime pas les valeurs d'attribut de la table pour les attributs d'objets de données qui le sont`null`. Si la `ignoreNulls()` méthode renvoie false, le SDK demande au service DynamoDB de supprimer les attributs de l'élément de la table. La valeur par défaut pour `ignoreNulls` est false.

L'instruction située après la ligne de commentaire 4 montre la variante d'une demande de suppression qui prend un objet de données. Le client amélioré extrait les valeurs clés avant d'envoyer la demande finale.

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

Les méthodes d'assistance suivantes fournissent les objets de données pour les `add*Item` paramètres.

#### Méthodes auxiliaires
<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;
    }
```

Les tables DynamoDB contiennent les éléments suivants avant l'exécution de l'exemple de code.

```
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'}
```

Les éléments suivants figurent dans les tableaux une fois l'exécution du code terminée.

```
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'}
```

L'élément de la ligne 2 a été supprimé et les lignes 3 et 5 indiquent les articles qui ont été placés. La ligne 4 montre la mise à jour de la ligne 1. La `price` valeur est la seule valeur qui a changé sur l'élément. Si la valeur renvoyée `ignoreNulls()` était fausse, la ligne 4 ressemblerait à la ligne suivante.

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

### Exemple de vérification de l'état
<a name="ddb-en-client-use-multiop-trans-writeitems-checkcond"></a>

L'exemple suivant montre l'utilisation d'un contrôle de condition. Un contrôle de condition est utilisé pour vérifier l'existence d'un article ou pour vérifier l'état d'attributs spécifiques d'un article dans la base de données. L'article enregistré lors du contrôle de condition ne peut pas être utilisé lors d'une autre opération de la transaction.

**Note**  
Vous ne pouvez pas cibler le même élément avec plusieurs opérations contenues dans la même transaction. Par exemple, vous ne pouvez pas effectuer de vérification de condition et essayer de mettre à jour le même article dans le cadre de la même transaction.

L'exemple montre un type d'opération de chaque type dans une demande d'écriture d'éléments transactionnelle. Après la ligne de commentaire 2, la `addConditionCheck()` méthode fournit la condition qui fait échouer la transaction si le `conditionExpression` paramètre est évalué à`false`. L'expression de condition renvoyée par la méthode indiquée dans le bloc des méthodes d'assistance vérifie si l'année de récompense du film n'`Sophie's Choice`est pas égale à`1982`. Si c'est le cas, l'expression est évaluée à `false` et la transaction échoue.

Ce guide aborde les [expressions](ddb-en-client-expressions.md) de manière approfondie dans une autre rubrique.

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

Les méthodes d'assistance suivantes sont utilisées dans l'exemple de code précédent.

#### Méthodes auxiliaires
<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;
    }
```

Les tables DynamoDB contiennent les éléments suivants avant l'exécution de l'exemple de code.

```
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'}
```

Les éléments suivants figurent dans les tableaux une fois l'exécution du code terminée.

```
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'}
```

Les éléments restent inchangés dans les tables car la transaction a échoué. La `actingYear` valeur du film `Sophie's Choice` est`1982`, comme indiqué à la ligne 2 des éléments du tableau avant l'appel de la `transactWriteItem()` méthode.

Pour saisir les informations d'annulation de la transaction, placez l'appel de `transactWriteItems()` méthode dans un `try` bloc et `catch` le [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). Après la ligne de commentaire 4 de l'exemple, le code enregistre chaque `[CancellationReason](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CancellationReason.html)` objet. Étant donné que le code suivant la ligne de commentaire 3 de l'exemple indique que des valeurs doivent être renvoyées pour l'élément à l'origine de l'échec de la transaction, le journal affiche les valeurs de base de données brutes pour l'élément `Sophie's Choice` vidéo.

```
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.)
```

### Exemple de condition de fonctionnement unique
<a name="ddb-en-client-use-multiop-trans-writeitems-opcondition"></a>

L'exemple suivant montre l'utilisation d'une condition pour une seule opération dans une demande de transaction. L'opération de suppression après la ligne de commentaire 1 contient une condition qui vérifie la valeur de l'élément cible de l'opération par rapport à la base de données. Dans cet exemple, l'expression de condition créée avec la méthode d'assistance après la ligne de commentaire 2 indique que l'élément doit être supprimé de la base de données si l'année active du film n'est pas égale à 2013.

Les [expressions](ddb-en-client-expressions.md) sont abordées plus loin dans ce guide.

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

Les méthodes d'assistance suivantes sont utilisées dans l'exemple de code précédent.

#### Méthodes auxiliaires
<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;
    }
```

Les tables DynamoDB contiennent les éléments suivants avant l'exécution de l'exemple de code.

```
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'}
```

Les éléments suivants figurent dans les tableaux une fois l'exécution du code terminée.

```
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'}
```

Les éléments restent inchangés dans les tables car la transaction a échoué. La `actingYear` valeur du film `Blue Jasmine` est `2013` celle indiquée à la ligne 2 dans la liste des éléments avant l'exécution de l'exemple de code.

Les lignes suivantes sont enregistrées dans la console.

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

# Utiliser des indices secondaires
<a name="ddb-en-client-use-secindex"></a>

Les index secondaires améliorent l'accès aux données en définissant des clés alternatives que vous pouvez utiliser dans les opérations de requête et de numérisation. Les indices secondaires globaux (GSI) possèdent une clé de partition et une clé de tri qui peuvent être différentes de celles de la table de base. En revanche, les indices secondaires locaux (LSI) utilisent la clé de partition de l'index principal.

## Annoter une classe de données avec des annotations d'index secondaires
<a name="ddb-en-client-use-secindex-annomodel"></a>

Les attributs qui participent aux index secondaires nécessitent l'`@DynamoDbSecondarySortKey`annotation `@DynamoDbSecondaryPartitionKey` ou.

La classe suivante montre les annotations pour deux indices. Le GSI nommé *SubjectLastPostedDateIndex*utilise l'`Subject`attribut pour la clé de partition et `LastPostedDateTime` pour la clé de tri. Le LSI nommé *ForumLastPostedDateIndex*utilise le `ForumName` comme clé de partition et `LastPostedDateTime` comme clé de tri.

Notez que l'`Subject`attribut joue un double rôle. Il s'agit de la clé de tri de la clé primaire et de la clé de partition du GSI nommé *SubjectLastPostedDateIndex*.

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

La `MessageThread` classe peut être utilisée comme classe de données pour l'[exemple de table de threads](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AppendixSampleTables.html) du manuel *Amazon DynamoDB Developer* Guide.

#### Importations
<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 +
                '}';
    }
}
```

## Création de l'index
<a name="ddb-en-client-use-secindex-confindex"></a>

À partir de la version 2.20.86 du SDK pour Java, la `createTable()` méthode génère automatiquement des index secondaires à partir des annotations de classes de données. Par défaut, tous les attributs de la table de base sont copiés dans un index et les valeurs de débit allouées sont de 20 unités de capacité de lecture et 20 unités de capacité d'écriture.

Toutefois, si vous utilisez une version du SDK antérieure à la version 2.20.86, vous devez créer l'index avec le tableau, comme indiqué dans l'exemple suivant. Cet exemple crée les deux index de la `Thread` table. Le paramètre [builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html) possède des méthodes pour configurer les deux types d'index, comme indiqué après les lignes de commentaire 1 et 2. Vous utilisez la `indexName()` méthode du générateur d'index pour associer les noms d'index spécifiés dans les annotations de classe de données au type d'index souhaité.

Ce code configure tous les attributs de table pour qu'ils apparaissent dans les deux index après les lignes de commentaires 3 et 4. De plus amples informations sur [les projections d'attributs](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html#LSI.Projections) sont disponibles dans le manuel du *développeur 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))
                )
        );
```

## Requête à l'aide d'un index
<a name="ddb-en-client-use-secindex-query"></a>

L’exemple suivant interroge l’index secondaire global *ForumLastPostedDateIndex*.

Après la ligne de commentaire 2, vous créez un [QueryConditional](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html)objet obligatoire lors de l'appel de la méthode [DynamoDbIndex.query ()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbIndex.html#query(java.util.function.Consumer)). 

Vous obtenez une référence à l'index que vous souhaitez interroger après la ligne de commentaire 3 en transmettant le nom de l'index. Après la ligne de commentaire 4, vous appelez la `query()` méthode sur l'index qui transmet l'`QueryConditional`objet. 

Vous configurez également la requête pour renvoyer trois valeurs d'attribut, comme indiqué après la ligne de commentaire 5. Si elle n'`attributesToProject()`est pas appelée, la requête renvoie toutes les valeurs d'attribut. Notez que les noms d'attributs spécifiés commencent par des lettres minuscules. Ces noms d'attributs correspondent à ceux utilisés dans la table, pas nécessairement aux noms d'attributs de la classe de données.

Après la ligne de commentaire 6, parcourez les résultats, enregistrez chaque élément renvoyé par la requête et stockez-le également dans la liste pour le renvoyer à l'appelant.

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

Les éléments suivants existent dans la base de données avant l'exécution de la requête.

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

Les instructions de journalisation des lignes 1 et 6 génèrent la sortie de console suivante.

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

La requête a renvoyé des éléments avec une `forumName` valeur de *Forum02* et une `lastPostedDateTime` valeur supérieure ou égale à *2023.03.31*. Les résultats affichent `message` des valeurs avec une chaîne vide, bien que les `message` attributs contiennent des valeurs dans l'index. Cela est dû au fait que l'attribut message n'a pas été projeté par le code après la ligne de commentaire 5. 

# Utiliser les fonctionnalités de cartographie avancées
<a name="ddb-en-client-adv-features"></a>

Découvrez les fonctionnalités avancées du schéma de table dans l'API DynamoDB Enhanced Client.

## Comprendre les types de schéma de table
<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)`est l'interface permettant d'accéder à la fonctionnalité de mappage de l'API DynamoDB Enhanced Client. Il peut mapper un objet de données vers et depuis une carte de [AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html). Un `TableSchema` objet doit connaître la structure de la table qu'il mappe. Ces informations de structure sont stockées dans un [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)objet.

L'API client améliorée comporte plusieurs implémentations de`TableSchema`, qui suivent. 

### Schéma de table généré à partir de classes annotées
<a name="ddb-en-client-adv-features-schema-mapped"></a>

La création d'une classe à `TableSchema` partir de classes annotées est une opération modérément coûteuse. Nous vous recommandons donc de ne le faire qu'une seule fois, au démarrage de l'application.

 [ BeanTableSchema ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/BeanTableSchema.html)   
Cette implémentation est construite sur la base des attributs et des annotations d'une classe de bean. Un exemple de cette approche est présenté dans la [section Commencer](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean).  
Si a ne `BeanTableSchema` se comporte pas comme prévu, activez la journalisation du débogage pour. `software.amazon.awssdk.enhanced.dynamodb.beans`

[ImmutableTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/ImmutableTableSchema.html)  
Cette implémentation est construite à partir d'une classe de données immuable. Cette approche est décrite dans la [Travaillez avec des classes de données immuables](ddb-en-client-use-immut.md) section.

### Schéma de table généré avec un générateur
<a name="ddb-en-client-adv-features-schema-static"></a>

Les éléments suivants `TableSchema` sont créés à partir du code à l'aide d'un générateur. Cette approche est moins coûteuse que celle qui utilise des classes de données annotées. L'approche du générateur évite l'utilisation d'annotations et ne nécessite pas de normes de JavaBean dénomination.

[StaticTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticTableSchema.html)  
Cette implémentation est conçue pour les classes de données mutables. La section de démarrage de ce guide explique comment [générer un à `StaticTableSchema` l'aide d'un générateur](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)  
De la même manière que vous créez un`StaticTableSchema`, vous générez une implémentation de ce type en `TableSchema` utilisant un [générateur](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticImmutableTableSchema.html) à utiliser avec des classes de données immuables.

### Schéma de table pour les données sans schéma fixe
<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)  
Contrairement aux autres implémentations de`TableSchema`, vous ne définissez pas d'attributs pour une `DocumentTableSchema` instance. En général, vous ne spécifiez que les clés primaires et les fournisseurs de convertisseurs d'attributs. Une `EnhancedDocument` instance fournit les attributs que vous créez à partir d'éléments individuels ou d'une chaîne JSON.

# Inclure ou exclure explicitement des attributs
<a name="ddb-en-client-adv-features-inex-attr"></a>

L'API DynamoDB Enhanced Client propose des annotations pour empêcher les attributs de classe de données de devenir des attributs d'une table. Avec l'API, vous pouvez également utiliser un nom d'attribut différent du nom d'attribut de classe de données.

## Exclure les attributs
<a name="ddb-en-client-adv-features-inex-attr-ex"></a>

Pour ignorer les attributs qui ne doivent pas être mappés à une table DynamoDB, marquez l'attribut avec l'annotation. `@DynamoDbIgnore`

```
private String internalKey;

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

## Inclure les attributs
<a name="ddb-en-client-adv-features-inex-attr-in"></a>

Pour modifier le nom d'un attribut utilisé dans la table DynamoDB, marquez-le avec `@DynamoDbAttribute` l'annotation et saisissez un autre nom.

```
private String internalKey;

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

# Conversion des attributs de contrôle
<a name="ddb-en-client-adv-features-conversion"></a>

Par défaut, un schéma de table fournit des convertisseurs pour de nombreux types Java courants via une implémentation par défaut de l'`[AttributeConverterProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverterProvider.html)`interface. Vous pouvez modifier le comportement général par défaut à l’aide d’une implémentation de `AttributeConverterProvider` personnalisée. Vous pouvez également modifier le convertisseur pour un seul attribut.

Pour une liste des convertisseurs disponibles, consultez la documentation Java de [AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html)l'interface.

## Fournir des fournisseurs de convertisseurs d'attributs personnalisés
<a name="ddb-en-client-adv-features-conversion-prov"></a>

Vous pouvez fournir un seul `AttributeConverterProvider` ou une chaîne de `AttributeConverterProvider` s ordonnés par le biais de l'`@DynamoDbBean``(converterProviders = {…})`annotation. Toute personnalisation `AttributeConverterProvider` doit étendre l'`AttributeConverterProvider`interface.

Notez que si vous fournissez votre propre chaîne de fournisseurs de convertisseurs d'attributs, vous remplacerez le fournisseur de conversion par défaut,`DefaultAttributeConverterProvider`. Si vous souhaitez utiliser les fonctionnalités du`DefaultAttributeConverterProvider`, vous devez l'inclure dans la chaîne. 

Il est également possible d'annoter le bean avec un tableau `{}` vide. Cela désactive l'utilisation de tous les fournisseurs de convertisseurs d'attributs, y compris le fournisseur par défaut. Dans ce cas, tous les attributs à mapper doivent disposer de leur propre convertisseur d'attributs.

L'extrait suivant montre un fournisseur de conversion unique.

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

}
```

L'extrait suivant montre l'utilisation d'une chaîne de fournisseurs de convertisseurs. La valeur par défaut du SDK étant fournie en dernier, elle a la priorité la plus basse.

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

}
```

Les constructeurs de schémas de tables statiques ont une `attributeConverterProviders()` méthode qui fonctionne de la même manière. Cela est illustré dans l'extrait suivant.

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

## Remplacer le mappage d'un seul attribut
<a name="ddb-en-client-adv-features-conversion-single"></a>

Pour modifier la façon dont un seul attribut est mappé, fournissez un `AttributeConverter` pour l'attribut. Cet ajout remplace tous les convertisseurs fournis `AttributeConverterProviders` dans le schéma de table. Cela ajoute un convertisseur personnalisé pour cet attribut uniquement. Les autres attributs, même ceux du même type, n'utiliseront pas ce convertisseur à moins qu'il ne soit explicitement spécifié pour ces autres attributs.

L'`@DynamoDbConvertedBy`annotation est utilisée pour spécifier la `AttributeConverter` classe personnalisée, comme indiqué dans l'extrait de code suivant.

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

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

Les générateurs de schémas statiques utilisent une `attributeConverter()` méthode de génération d'attributs équivalente. Cette méthode prend une instance d'un `AttributeConverter` comme le montre ce qui suit.

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

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

Cet exemple montre une `AttributeConverterProvider` implémentation qui fournit un convertisseur d'attributs pour les [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)objets. 

La `SimpleUser` classe suivante contient un attribut nommé `lastUsedCookie` qui est une instance de`HttpCookie`.

Le paramètre des `@DynamoDbBean` annotations répertorie les deux `AttributeConverterProvider` classes qui fournissent des convertisseurs.

------
#### [ 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`L'exemple suivant fournit une instance de`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);
        }
    }
```

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

Dans la `transformFrom()` méthode de la `HttpCookieConverter` classe suivante, le code reçoit une `HttpCookie` instance et la transforme en une carte DynamoDB stockée sous forme d'attribut.

La `transformTo()` méthode reçoit un paramètre de carte DynamoDB, puis appelle le constructeur qui a besoin d'un `HttpCookie` nom et d'une valeur.

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

# Modifier le comportement de mise à jour des attributs
<a name="ddb-en-client-adv-features-upd-behavior"></a>

Vous pouvez personnaliser le comportement de mise à jour des attributs individuels lorsque vous effectuez une opération de *mise à jour*. [UpdateItem () et () sont des exemples d'opérations de mise à jour](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#updateItem(T)) [dans l'API DynamoDB Enhanced Client. transactWriteItems](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))

Imaginons, par exemple, que vous souhaitiez enregistrer un fichier *créé sur* horodatage dans votre dossier. Toutefois, vous souhaitez que sa valeur ne soit écrite que s'il n'existe aucune valeur existante pour l'attribut dans la base de données. Dans ce cas, vous utilisez le comportement de `[WRITE\$1IF\$1NOT\$1EXISTS](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html#WRITE_IF_NOT_EXISTS)` mise à jour.

L'exemple suivant montre l'annotation qui ajoute le comportement à l'`createdOn`attribut.

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

Vous pouvez déclarer le même comportement de mise à jour lorsque vous créez un schéma de table statique, comme indiqué dans l'exemple suivant après la ligne de commentaire 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();
```

# Aplatir les attributs des autres classes
<a name="ddb-en-client-adv-features-flatmap"></a>

Si les attributs de votre table sont répartis dans plusieurs classes Java différentes, que ce soit par héritage ou par composition, l'API DynamoDB Enhanced Client permet de regrouper les attributs en une seule classe.

## Utiliser l'héritage
<a name="ddb-en-client-adv-features-flatmap-inheritance"></a>

Si vos classes utilisent l'héritage, appliquez les approches suivantes pour aplatir la hiérarchie.

### Utiliser des haricots annotés
<a name="ddb-en-client-adv-features-flatmap-inheritance-anno"></a>

Pour l'approche d'annotation, les deux classes doivent porter l'`@DynamoDbBean`annotation et une classe doit porter une ou plusieurs annotations de clé primaire.

Vous trouverez ci-dessous des exemples de classes de données dotées d'une relation d'héritage.

------
#### [ 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 ]

L'[`onMethod`option](https://projectlombok.org/features/experimental/onX) de Lombok copie les annotations DynamoDB basées sur les attributs, telles que, sur le code généré. `@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;
}
```

------

### Utiliser des schémas statiques
<a name="ddb-en-client-adv-features-flatmap-inheritance-static"></a>

Pour l'approche du schéma statique, utilisez la `extend()` méthode du générateur pour réduire les attributs de la classe parent sur ceux de la classe enfant. Ceci est affiché après la ligne de commentaire 1 dans l'exemple suivant.

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

L'exemple de schéma statique précédent utilise les classes de données suivantes. Comme le mappage est défini lorsque vous créez le schéma de table statique, les classes de données ne nécessitent pas d'annotations.

#### Classes de données
<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;
}
```

------

## Utiliser la composition
<a name="ddb-en-client-adv-features-flatmap-comp"></a>

Si vos classes utilisent la composition, appliquez les approches suivantes pour aplatir la hiérarchie.

### Utiliser des haricots annotés
<a name="ddb-en-client-adv-features-flatmap-comp-anno"></a>

L'`@DynamoDbFlatten`annotation aplatit la classe contenue.

Les exemples de classes de données suivants utilisent l'`@DynamoDbFlatten`annotation pour ajouter efficacement tous les attributs de la `GenericRecord` classe contenue à la `Customer` classe.

------
#### [ 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;
}
```

------

Vous pouvez utiliser l'annotation aplatir pour aplatir autant de classes éligibles que nécessaire. Les contraintes suivantes s’appliquent :
+ Tous les noms d'attributs doivent être uniques une fois aplatis.
+ Il ne doit jamais y avoir plus d'une clé de partition, clé de tri ou nom de table.

### Utiliser des schémas statiques
<a name="ddb-en-client-adv-features-flatmap-comp-static"></a>

Lorsque vous créez un schéma de table statique, utilisez la `flatten()` méthode du générateur. Vous fournissez également les méthodes getter et setter qui identifient la classe contenue.

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

L'exemple de schéma statique précédent utilise les classes de données suivantes.

#### Classes de données
<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;
}
```

------

Vous pouvez utiliser le modèle Builder pour aplatir autant de classes éligibles que nécessaire.

## Implications pour les autres codes
<a name="ddb-en-client-adv-features-flatmap-compare"></a>

Lorsque vous utilisez l'`@DynamoDbFlatten`attribut (ou la méthode du `flatten()` générateur), l'élément de DynamoDB contient un attribut pour chaque attribut de l'objet composé. Il inclut également les attributs de l'objet composant. 

En revanche, si vous annotez une classe de données avec une classe composée et que vous ne l'utilisez pas`@DynamoDbFlatten`, l'élément est enregistré avec l'objet composé en tant qu'attribut unique.

Par exemple, comparez la `Customer` classe indiquée dans l'[exemple d'aplatissement avec la composition avec](#ddb-en-client-adv-features-flatmap-comp-anno) et sans aplatissement de l'attribut. `record` Vous pouvez visualiser la différence avec JSON, comme indiqué dans le tableau suivant.


****  

| Avec aplatissement | Sans aplatir | 
| --- | --- | 
| 3 attributs | 2 attributs | 
|  <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>  | 

La différence devient importante si vous disposez d'un autre code accédant à la table DynamoDB qui devrait trouver certains attributs.

# Travaillez avec des attributs tels que des beans, des cartes, des listes et des ensembles
<a name="ddb-en-client-adv-features-nested"></a>

Une définition de bean, telle que la `Person` classe illustrée ci-dessous, peut définir des propriétés (ou des attributs) qui font référence à des types dotés d'attributs supplémentaires. Par exemple, dans la `Person` classe, se `mainAddress` trouve une propriété qui fait référence à un `Address` bean qui définit des attributs de valeur supplémentaires. `addresses`fait référence à une carte Java, dont les éléments font référence à des `Address` beans. Ces types complexes peuvent être considérés comme des conteneurs d'attributs simples que vous utilisez pour leur valeur de données dans le contexte de DynamoDB. 

*DynamoDB désigne les propriétés de valeur des éléments imbriqués, tels que les cartes, les listes ou les beans, en tant qu'attributs imbriqués.* *Le guide du [développeur Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) fait référence à la forme enregistrée d'une carte, d'une liste ou d'un bean Java en tant que type de document.* Les attributs simples que vous utilisez pour leur valeur de données en Java sont appelés *types scalaires* dans DynamoDB. Ensembles, qui contiennent plusieurs éléments scalaires du même type, appelés *types d'ensembles*. 

Il est important de savoir que l'API DynamoDB Enhanced Client convertit une propriété qui est un bean en un type de document ArcMap DynamoDB lors de son enregistrement.

## classe `Person`
<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 +
               '}';
    }
}
```

## classe `Address`
<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 + '\'' +
                '}';
    }
}
```

## classe `PhoneNumber`
<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 + '\'' +
                '}';
    }
}
```

## Enregistrer des types complexes
<a name="ddb-en-client-adv-features-nested-mapping"></a>

### Utiliser des classes de données annotées
<a name="ddb-en-client-adv-features-nested-map-anno"></a>

Pour enregistrer les attributs imbriqués des classes personnalisées, il suffit de les annoter. La `Address` classe et la `PhoneNumber` classe affichées précédemment sont annotées uniquement avec l'`@DynamoDbBean`annotation. Lorsque l'API DynamoDB Enhanced Client crée le schéma de table pour la classe à `Person` l'aide de l'extrait suivant, l'API découvre l'utilisation des classes et `PhoneNumber` et crée les mappages `Address` correspondants pour fonctionner avec DynamoDB.

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

### Utiliser des schémas abstraits avec des constructeurs
<a name="ddb-en-client-adv-features-nested-map-builder"></a>

L'approche alternative consiste à utiliser des générateurs de schémas de tables statiques pour chaque classe de bean imbriquée, comme indiqué dans le code suivant.

Les schémas de table des `PhoneNumber` classes `Address` et sont abstraits dans le sens où ils ne peuvent pas être utilisés avec une table DynamoDB. Cela est dû au fait qu'ils ne disposent pas de définitions pour la clé primaire. Ils sont toutefois utilisés comme schémas imbriqués dans le schéma de table de la `Person` classe.

Après les lignes de commentaire 1 et 2 de la définition de`PERSON_TABLE_SCHEMA`, vous pouvez voir le code qui utilise les schémas de table abstraits. L'utilisation de `documentOf` dans la `EnhanceType.documentOf(...)` méthode n'indique pas que la méthode renvoie un `EnhancedDocument` type d'API de document améliorée. Dans ce contexte, la `documentOf(...)` méthode renvoie un objet qui sait comment mapper son argument de classe vers et depuis les attributs de table DynamoDB en utilisant l'argument de schéma de table.

#### Code de schéma statique
<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();
```

## Attributs de projet de types complexes
<a name="ddb-en-client-adv-features-nested-projection"></a>

Pour les `scan()` méthodes `query()` et, vous pouvez spécifier les attributs que vous souhaitez voir renvoyés dans les résultats en utilisant des appels de méthode tels que `addNestedAttributeToProject()` et`attributesToProject()`. L'API DynamoDB Enhanced Client convertit les paramètres d'appel de méthode Java [en expressions de projection](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html) avant l'envoi de la demande.

L'exemple suivant remplit le `Person` tableau avec deux éléments, puis exécute trois opérations de numérisation. 

Le premier scan accède à tous les éléments du tableau afin de comparer les résultats aux autres opérations d'analyse. 

Le second scan utilise la méthode du [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))générateur pour renvoyer uniquement la valeur de `street` l'attribut.

La troisième opération d'analyse utilise la méthode du [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...))générateur pour renvoyer les données de l'attribut de premier niveau,`hobbies`. Le type d'attribut de `hobbies` est une liste. Pour accéder à des éléments de liste individuels, effectuez une `get()` opération sur la liste.

```
        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
```

**Note**  
Si la `attributesToProject()` méthode suit une autre méthode de création qui ajoute les attributs que vous souhaitez projeter, la liste des noms d'attributs fournie au `attributesToProject()` remplace tous les autres noms d'attributs.  
Une analyse effectuée avec l'`ScanEnhancedRequest`instance figurant dans l'extrait suivant renvoie uniquement les données relatives aux loisirs.  

```
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]}
```
L'extrait de code suivant utilise d'abord la `attributesToProject()` méthode. Cet ordre préserve tous les autres attributs demandés.  

```
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]}
```

## Utiliser des types complexes dans les expressions
<a name="ddb-en-client-adv-features-nested-expressions"></a>

Vous pouvez utiliser des types complexes dans les expressions, telles que les expressions de filtre et les expressions de condition, en utilisant des opérateurs de déréférencement pour parcourir la structure du type complexe. Pour les objets et les cartes, utilisez le `. (dot)` et pour les éléments de liste `[n]` (crochets autour du numéro de séquence de l'élément). Vous ne pouvez pas faire référence à des éléments individuels d'un ensemble, mais vous pouvez utiliser la [`contains`fonction](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions).

L'exemple suivant montre deux expressions de filtre utilisées dans les opérations de numérisation. Les expressions de filtre spécifient les conditions de correspondance pour les éléments que vous souhaitez voir apparaître dans les résultats. L'exemple utilise`Person`,`Address`, et `PhoneNumber` les classes présentés précédemment.

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

### Méthode d'assistance qui remplit le tableau
<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);
    }
```

### Représentation JSON des éléments de la base de données
<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"
  }
 ]
}
```

## Mettre à jour les éléments contenant des types complexes
<a name="ddb-en-client-adv-features-nested-updates"></a>

Pour mettre à jour un élément contenant des types complexes, vous avez deux approches de base :
+ Approche 1 : récupérez d'abord l'élément (en utilisant`getItem`), mettez à jour l'objet, puis appelez`DynamoDbTable#updateItem`.
+ Approche 2 : Ne récupérez pas l'élément, mais créez une nouvelle instance, définissez les propriétés que vous souhaitez mettre à jour et soumettez l'instance `DynamoDbTable#updateItem` en définissant la valeur appropriée de [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). Cette approche ne nécessite pas que vous récupériez l'élément avant de le mettre à jour.

Les exemples présentés dans cette section utilisent les `PhoneNumber` classes `Person``Address`,, et présentées précédemment.

### Approche de mise à jour 1 : récupération, puis mise à jour
<a name="ddb-en-client-adv-features-nested-updates-retreive"></a>

En utilisant cette approche, vous vous assurez qu'aucune donnée n'est perdue lors de la mise à jour. L'API DynamoDB Enhanced Client recrée le bean avec les attributs de l'élément enregistré dans DynamoDB, y compris les valeurs de types complexes. Vous devez ensuite utiliser les getters et setters pour mettre à jour le bean. L'inconvénient de cette approche est le coût que vous devez engager pour récupérer l'article en premier.

L'exemple suivant montre qu'aucune donnée n'est perdue si vous récupérez l'élément avant de le mettre à jour.

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

### Approche de mise à jour 2 : utilisez une `IgnoreNullsMode` énumération sans récupérer l'élément au préalable
<a name="ddb-en-client-adv-features-nested-updates-nullmode"></a>

Pour mettre à jour un élément dans DynamoDB, vous pouvez fournir un nouvel objet contenant uniquement les propriétés que vous souhaitez mettre à jour et laisser les autres valeurs nulles. Avec cette approche, vous devez être conscient de la manière dont les valeurs nulles de l'objet sont traitées par le SDK et de la manière dont vous pouvez contrôler le comportement.

Pour spécifier les propriétés à valeur nulle que vous souhaitez que le SDK ignore, fournissez une `IgnoreNullsMode` énumération lorsque vous créez le. [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) À titre d'exemple d'utilisation de l'une des valeurs énumérées, l'extrait de code suivant utilise le 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"
    }
  }
*/
```

[Le guide du développeur Amazon DynamoDB contient plus d'informations sur les expressions de mise à jour.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html)

#### Descriptions des `IgnoreNullsMode` options
<a name="ignore-nulls-mode-descriptions"></a>
+ `IgnoreNullsMode.SCALAR_ONLY`- Utilisez ce paramètre pour mettre à jour les attributs scalaires à tous les niveaux. Le SDK crée une instruction de mise à jour qui envoie uniquement des attributs scalaires non nuls à DynamoDB. Le SDK ignore les attributs scalaires à valeur nulle d'un bean ou d'une carte, en conservant la valeur enregistrée dans DynamoDB.

  Lorsque vous mettez à jour un attribut scalaire de map ou bean, la carte doit déjà exister dans DynamoDB. Si vous ajoutez une carte ou un bean à l'objet qui n'existe pas déjà pour cet objet dans DynamoDB, le *message « Le chemin du document indiqué dans l'expression de mise à jour n'est pas `DynamoDbException` valide pour la mise à jour* » s'affiche. Vous devez utiliser `MAPS_ONLY` le mode pour ajouter un bean ou une carte à DynamoDB avant de mettre à jour l'un de ses attributs.
+ `IgnoreNullsMode.MAPS_ONLY`- Utilisez ce paramètre pour ajouter ou remplacer des propriétés qui sont un bean ou une carte. Le SDK remplace ou ajoute toute carte ou bean fourni dans l'objet. Tous les beans ou cartes dont la valeur est nulle dans l'objet sont ignorés, ce qui permet de conserver la carte qui existe dans DynamoDB.
+ `IgnoreNullsMode.DEFAULT`- Avec ce paramètre, le SDK n'ignore jamais les valeurs nulles. Les attributs scalaires de tous les niveaux qui sont nuls sont mis à jour à zéro. Le SDK met à jour toute propriété de type bean, map, list ou set dont la valeur est nulle dans l'objet en lui attribuant la valeur null dans DynamoDB. Lorsque vous utilisez ce mode (ou que vous n'en fournissez aucun puisqu'il s'agit du mode par défaut), vous devez d'abord récupérer l'élément afin que les valeurs fournies dans l'objet pour la mise à jour dans DynamoDB ne soient pas définies sur null, sauf si vous avez l'intention de définir les valeurs sur null.

Dans tous les modes, si vous fournissez un objet `updateItem` dont la liste ou l'ensemble n'est pas nul, la liste ou l'ensemble est enregistré dans DynamoDB. 

#### Pourquoi les modes ?
<a name="ddb-en-client-adv-features-nested-updates-nullmodes-why"></a>

Lorsque vous fournissez à un objet un bean ou un mappage vers la `updateItem` méthode, le SDK ne peut pas dire s'il doit utiliser les valeurs des propriétés du bean (ou les valeurs d'entrée dans la carte) pour mettre à jour l'élément, ou si l'intégralité bean/map doit remplacer ce qui a été enregistré dans DynamoDB.

À partir de notre exemple précédent qui montre d'abord la récupération de l'élément, essayons de mettre à jour l'`city`attribut de `mainAddress` sans la récupération.

```
/* 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'.
*/
```

Les deux exemples suivants montrent les utilisations des valeurs `SCALAR_ONLY` énumérées `MAPS_ONLY` et. `MAPS_ONLY`ajoute une carte et `SCALAR_ONLY` met à jour une carte.

##### Exemple de `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.
    }
```

Reportez-vous au tableau suivant pour savoir quelles valeurs nulles sont ignorées pour chaque mode. Vous pouvez souvent travailler avec l'un ou `SCALAR_ONLY` l'autre`MAPS_ONLY`, sauf lorsque vous travaillez avec des beans ou des cartes.


**Quelles propriétés à valeur nulle de l'objet soumis le SDK `updateItem` ignore-t-il pour chaque mode ?**  

| Type de propriété | en mode SCALAR\$1ONLY | en mode MAPS\$1ONLY | en mode DEFAULT | 
| --- | --- | --- | --- | 
| Meilleur scalaire | Oui | Oui | Non | 
| Bean ou carte | Oui | Oui | Non | 
| Valeur scalaire d'un bean ou d'une entrée de carte | Oui1 | No2 | Non | 
| Liste ou ensemble | Oui | Oui | Non | 

1 Cela suppose que la carte existe déjà dans DynamoDB. Toute valeur scalaire (nulle ou non nulle) du bean ou de la carte que vous fournissez dans l'objet à mettre à jour nécessite qu'un chemin d'accès à la valeur existe dans DynamoDB. Le SDK construit un chemin d'accès à l'attribut en utilisant l'opérateur de `. (dot)` déréférencement avant de soumettre la demande.

2 Puisque vous utilisez le `MAPS_ONLY` mode pour remplacer complètement ou ajouter un bean ou une map, toutes les valeurs nulles du bean ou de la map sont conservées dans la map enregistrée dans DynamoDB.

# Préservez les objets vides avec `@DynamoDbPreserveEmptyObject`
<a name="ddb-en-client-adv-features-empty"></a>

Si vous enregistrez un bean dans Amazon DynamoDB avec des objets vides et que vous souhaitez que le SDK recrée les objets vides lors de leur extraction, annotez le getter du bean interne avec. `@DynamoDbPreserveEmptyObject`

Pour illustrer le fonctionnement de l'annotation, l'exemple de code utilise les deux beans suivants.

## Exemple de haricots
<a name="ddb-en-client-adv-features-empty-ex1"></a>

La classe de données suivante contient deux `InnerBean` champs. La méthode getter`getInnerBeanWithoutAnno()`, n'est pas annotée avec. `@DynamoDbPreserveEmptyObject` La `getInnerBeanWithAnno()` méthode est annotée.

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

Les instances de la `InnerBean` classe suivante sont des champs de `MyBean` et sont initialisées en tant qu'objets vides dans l'exemple de code.

```
@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 + '\'' +
                '}';
    }
}
```

L'exemple de code suivant enregistre un `MyBean` objet avec des beans internes initialisés dans DynamoDB, puis récupère l'élément. La sortie enregistrée indique que le n'`innerBeanWithoutAnno`est pas initialisé, mais qu'il `innerBeanWithAnno` a été créé.

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

## Schéma statique alternatif
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

Vous pouvez utiliser la `StaticTableSchema` version suivante des schémas de table à la place des annotations sur les beans.

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

# Évitez de sauvegarder les attributs nuls des objets imbriqués
<a name="ddb-en-client-adv-features-ignore-null"></a>

Vous pouvez ignorer les attributs nuls des objets imbriqués lorsque vous enregistrez un objet de classe de données dans DynamoDB en appliquant l'annotation. `@DynamoDbIgnoreNulls` En revanche, les attributs de niveau supérieur contenant des valeurs nulles ne sont jamais enregistrés dans la base de données.

Pour illustrer le fonctionnement de l'annotation, l'exemple de code utilise les deux beans suivants.

## Exemple de haricots
<a name="ddb-en-client-adv-features-ignore-null-ex1"></a>

La classe de données suivante contient deux `InnerBean` champs. La méthode getter`getInnerBeanWithoutAnno()`, n'est pas annotée. La `getInnerBeanWithIgnoreNullsAnno()` méthode est annotée avec`@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();
    }
}
```

Les instances de la `InnerBean` classe suivante sont des champs de `MyBean` et sont utilisées dans l'exemple de code suivant.

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

L'exemple de code suivant crée un `InnerBean` objet et attribue une valeur à un seul de ses deux attributs. 

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

Pour visualiser les données de bas niveau envoyées à DynamoDB, le code enregistre la carte attributaire avant d'enregistrer l'objet. `MyBean`

La sortie enregistrée montre qu'elle `innerBeanWithIgnoreNullsAnno` produit un attribut,

```
innerBeanWithIgnoreNullsAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200)})
```

L'`innerBeanWithoutAnno`instance génère deux attributs. L'un des attributs a une valeur de 200 et l'autre est un attribut de valeur nulle.

```
innerBeanWithoutAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200), innerBeanFieldString=AttributeValue(NUL=true)})
```

## Représentation JSON de la carte attributaire
<a name="ddb-en-client-adv-features-ignore-null-ex2"></a>

La représentation JSON suivante permet de visualiser plus facilement les données enregistrées dans DynamoDB.

```
{
  "id": {
    "S": "1"
  },
  "innerBeanWithIgnoreNullsAnno": {
    "M": {
      "innerBeanFieldInteger": {
        "N": "200"
      }
    }
  },
  "innerBeanWithoutAnno": {
    "M": {
      "innerBeanFieldInteger": {
        "N": "200"
      },
      "innerBeanFieldString": {
        "NULL": true
      }
    }
  }
}
```

## Schéma statique alternatif
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

Vous pouvez utiliser la `StaticTableSchema` version suivante des schémas de table pour mettre en place des annotations de classe de données.

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

# Travaillez avec des documents JSON avec l'API de document améliorée pour DynamoDB
<a name="ddb-en-client-doc-api"></a>

L'[API de document améliorée](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) pour AWS SDK for Java 2.x est conçue pour fonctionner avec des données orientées document qui n'ont aucun schéma fixe. Toutefois, il vous permet également d'utiliser des classes personnalisées pour mapper des attributs individuels.

 L'Enhanced Document API est le successeur de l'[API Document](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html) de la AWS SDK pour Java v1.x.

**Contents**
+ [Commencez à utiliser l'API Enhanced Document](ddb-en-client-doc-api-steps.md)
  + [Créez un `DocumentTableSchema` et un `DynamoDbTable`](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema)
+ [Créez des documents améliorés](ddb-en-client-doc-api-steps-create-ed.md)
  + [Construire à partir d'une chaîne JSON](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromJson)
  + [Construisez à partir d'éléments individuels](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts)
+ [Effectuer des opérations CRUD](ddb-en-client-doc-api-steps-use.md)
+ [Accédez aux attributs de document améliorés sous forme d'objets personnalisés](ddb-en-client-doc-api-convert.md)
+ [Utiliser et `EnhancedDocument` sans DynamoDB](ddb-en-client-doc-api-standalone.md)

# Commencez à utiliser l'API Enhanced Document
<a name="ddb-en-client-doc-api-steps"></a>

L'API de document améliorée nécessite les mêmes [dépendances](ddb-en-client-getting-started.md#ddb-en-client-gs-dep) que celles requises pour l'API client améliorée DynamoDB. Cela nécessite également une [`DynamoDbEnhancedClient`instance](ddb-en-client-getting-started-dynamodbTable.md#ddb-en-client-getting-started-dynamodbTable-eclient), comme indiqué au début de cette rubrique.

Étant donné que l'API Enhanced Document a été publiée avec la version 2.20.3 du AWS SDK for Java 2.x, vous avez besoin de cette version ou d'une version ultérieure.

## Créez un `DocumentTableSchema` et un `DynamoDbTable`
<a name="ddb-en-client-doc-api-steps-createschema"></a>

Pour appeler des commandes sur une table DynamoDB à l'aide de l'API Enhanced Document, associez la table à un objet de ressource < > [DynamoDbTablecôté client EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html). 

La `table()` méthode du client amélioré crée une `DynamoDbTable<EnhancedDocument>` instance et nécessite des paramètres pour le nom de la table DynamoDB et un. `DocumentTableSchema` 

Le générateur d'un [DocumentTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/DocumentTableSchema.html)nécessite une clé d'index principale et un ou plusieurs fournisseurs de convertisseurs d'attributs. La `AttributeConverterProvider.defaultProvider()` méthode fournit des convertisseurs pour les [types par défaut](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/package-summary.html). Il doit être spécifié même si vous fournissez un fournisseur de convertisseur d'attributs personnalisé. Vous pouvez ajouter une clé d'index secondaire facultative au générateur.

L'extrait de code suivant montre le code qui génère la représentation côté client d'une table DynamoDB qui stocke des objets sans schéma. `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.
```

Ce qui suit montre la représentation JSON d'un `person` objet utilisé dans cette section.

### `person`Objet JSON
<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"
    }
  ]
}
```

# Créez des documents améliorés
<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)` représente un objet de type document doté d'une structure complexe avec des attributs imbriqués. An `EnhancedDocument` nécessite des attributs de haut niveau qui correspondent aux attributs de clé primaire spécifiés pour le`DocumentTableSchema`. Le contenu restant est arbitraire et peut être composé d'attributs de haut niveau ou d'attributs profondément imbriqués.

Vous créez une `EnhancedDocument` instance à l'aide d'un générateur qui propose plusieurs méthodes pour ajouter des éléments.

## Construire à partir d'une chaîne JSON
<a name="ddb-en-client-doc-api-steps-create-ed-fromJson"></a>

Avec une chaîne JSON, vous pouvez créer un appel de méthode `EnhancedDocument` en un. L'extrait suivant crée une chaîne `EnhancedDocument` à partir d'une chaîne JSON renvoyée par la méthode d'`jsonPerson()`assistance. La `jsonPerson()` méthode renvoie la version de chaîne JSON de l'[objet person](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema-obj) affiché précédemment.

```
EnhancedDocument document = 
        EnhancedDocument.builder()
                        .json( jsonPerson() )
                        .build());
```

## Construisez à partir d'éléments individuels
<a name="ddb-en-client-doc-api-steps-create-ed-fromparts"></a>

Vous pouvez également créer une `EnhancedDocument` instance à partir de composants individuels à l'aide des méthodes de type sécurisé du générateur.

L'exemple suivant crée un document `person` amélioré similaire au document amélioré créé à partir de la chaîne JSON de l'exemple précédent.

```
        /* 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();
```

### Méthodes auxiliaires
<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"));

    }
```

# Effectuer des opérations CRUD
<a name="ddb-en-client-doc-api-steps-use"></a>

Après avoir défini une `EnhancedDocument` instance, vous pouvez l'enregistrer dans une table DynamoDB. L'extrait de code suivant utilise le [PersonDocument](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts) créé à partir d'éléments individuels.

```
documentDynamoDbTable.putItem(personDocument);
```

Après avoir lu une instance de document améliorée depuis DynamoDB, vous pouvez extraire les valeurs d'attribut individuelles à l'aide de getters, comme indiqué dans l'extrait de code suivant qui accède aux données enregistrées depuis le. `personDocument` Vous pouvez également extraire le contenu complet dans une chaîne JSON, comme indiqué dans la dernière partie de l'exemple de code.

```
        // 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`les instances peuvent être utilisées avec n'importe quelle méthode `[DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)` ou [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html)à la place de classes de données mappées.

# Accédez aux attributs de document améliorés sous forme d'objets personnalisés
<a name="ddb-en-client-doc-api-convert"></a>

En plus de fournir une API pour lire et écrire des attributs avec des structures sans schéma, l'API Enhanced Document vous permet de convertir des attributs depuis et vers des instances de classes personnalisées.

L'API de document améliorée utilise `AttributeConverterProvider` les valeurs s et `AttributeConverter` s affichées dans la section de [conversion des attributs de contrôle](ddb-en-client-adv-features-conversion.md) dans le cadre de l'API client améliorée DynamoDB.

Dans l'exemple suivant, nous utilisons a `CustomAttributeConverterProvider` avec sa `AddressConverter` classe imbriquée pour convertir `Address` des objets. 

Cet exemple montre que vous pouvez mélanger des données provenant de classes et des données provenant de structures créées selon les besoins. Cet exemple montre également que les classes personnalisées peuvent être utilisées à n'importe quel niveau d'une structure imbriquée. Les `Address` objets de cet exemple sont des valeurs utilisées dans une carte.

```
    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'}
```

## Code de la `CustomAttributeConverterProvider`
<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;
        }
    }
}
```

## classe `Address`
<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;
                  }
                  }
```

## Méthode d'assistance qui fournit des adresses
<a name="ddb-en-client-doc-api-convert-helper"></a>

La méthode d'assistance suivante fournit la carte qui utilise des `Address` instances personnalisées pour les valeurs plutôt que des `Map<String, String>` instances génériques pour les valeurs.

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

# Utiliser et `EnhancedDocument` sans DynamoDB
<a name="ddb-en-client-doc-api-standalone"></a>

Bien que vous utilisiez généralement une instance d'un `EnhancedDocument` pour lire et écrire des éléments DynamoDB de type document, elle peut également être utilisée indépendamment de DynamoDB. 

Vous pouvez `EnhancedDocuments` les utiliser pour leur capacité à convertir des chaînes JSON ou des objets personnalisés en cartes de bas niveau, `AttributeValues` comme indiqué dans l'exemple suivant.

```
    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'}
   */
```

**Note**  
Lorsque vous utilisez un document amélioré indépendant d'une table DynamoDB, assurez-vous de définir explicitement les fournisseurs de convertisseurs d'attributs dans le générateur.  
En revanche, le schéma de table de documents fournit les fournisseurs de conversion lorsqu'un document amélioré est utilisé avec une table DynamoDB.

# Utiliser des extensions pour personnaliser les opérations du client DynamoDB Enhanced
<a name="ddb-en-client-extensions"></a>

L'API DynamoDB Enhanced Client prend en charge les extensions de plug-in qui fournissent des fonctionnalités allant au-delà des opérations de mappage. Les extensions utilisent deux méthodes hook pour modifier les données lors des opérations de lecture et d'écriture :
+ `beforeWrite()`- Modifie une opération d'écriture avant qu'elle ne se produise
+ `afterRead()`- Modifie les résultats d'une opération de lecture après qu'elle se soit produite

Certaines opérations (telles que les mises à jour d'éléments) effectuent à la fois une écriture puis une lecture. Les deux méthodes hook sont donc appelées.

## Comment les extensions sont chargées
<a name="ddb-en-client-extensions-loading"></a>

Les extensions sont chargées dans l'ordre que vous spécifiez dans le générateur de clients amélioré. L'ordre de chargement peut être important car une extension peut agir sur des valeurs transformées par une extension précédente.

Par défaut, le client amélioré charge deux extensions :
+ `[VersionedRecordExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtension.html)`- Assure un verrouillage optimiste
+ `[AtomicCounterExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/AtomicCounterExtension.html)`- Incrémente automatiquement les attributs du compteur

Vous pouvez modifier le comportement par défaut à l'aide du générateur de clients amélioré et charger n'importe quelle extension. Vous pouvez également n'en spécifier aucune si vous ne souhaitez pas utiliser les extensions par défaut.

**Important**  
Si vous chargez vos propres extensions, le client amélioré ne charge aucune extension par défaut. Si vous souhaitez obtenir le comportement fourni par l'une ou l'autre des extensions par défaut, vous devez l'ajouter explicitement à la liste des extensions.

L'exemple suivant montre comment charger une extension personnalisée nommée d'`verifyChecksumExtension`après le`VersionedRecordExtension`. Le n'`AtomicCounterExtension`est pas chargé dans cet exemple.

```
DynamoDbEnhancedClientExtension versionedRecordExtension = VersionedRecordExtension.builder().build();

DynamoDbEnhancedClient enhancedClient = 
    DynamoDbEnhancedClient.builder()
                          .dynamoDbClient(dynamoDbClient)
                          .extensions(versionedRecordExtension, verifyChecksumExtension)
                          .build();
```

## Détails et configuration des extensions disponibles
<a name="ddb-en-client-extensions-details"></a>

Les sections suivantes fournissent des informations détaillées sur chaque extension disponible dans le SDK.

### Mettez en œuvre un verrouillage optimiste avec le `VersionedRecordExtension`
<a name="ddb-en-client-extensions-VRE"></a>

L'`VersionedRecordExtension`extension permet un verrouillage optimiste en incrémentant et en suivant le numéro de version d'un élément au fur et à mesure que les éléments sont écrits dans la base de données. Une condition est ajoutée à chaque écriture qui entraîne l'échec de l'écriture si le numéro de version de l'élément persistant réel ne correspond pas à la valeur lue pour la dernière fois par l'application.

#### Configuration
<a name="ddb-en-client-extensions-VRE-conf"></a>

Pour spécifier l'attribut à utiliser pour suivre le numéro de version de l'article, balisez un attribut numérique dans le schéma du tableau.

L'extrait suivant indique que l'`version`attribut doit contenir le numéro de version de l'article.

```
    @DynamoDbVersionAttribute
    public Integer getVersion() {...};
    public void setVersion(Integer version) {...};
```

L'approche équivalente du schéma de table statique est illustrée dans l'extrait suivant.

```
    .addAttribute(Integer.class, a -> a.name("version")
                                       .getter(Customer::getVersion)
                                       .setter(Customer::setVersion)
                                        // Apply the 'version' tag to the attribute.
                                       .tags(VersionedRecordExtension.AttributeTags.versionAttribute())
```

#### Comment ça marche
<a name="ddb-en-client-extensions-VRE-how-it-works"></a>

Le verrouillage optimiste avec le `VersionedRecordExtension` a l'impact suivant sur ces derniers `DynamoDbEnhancedClient` et sur `DynamoDbTable` les méthodes :

**`putItem`**  
Une valeur de version initiale de 0 est attribuée aux nouveaux éléments. Cela peut être configuré avec`@DynamoDbVersionAttribute(startAt = X)`.

**`updateItem`**  
Si vous récupérez un élément, mettez à jour une ou plusieurs de ses propriétés et tentez d'enregistrer les modifications, l'opération n'aboutit que si le numéro de version côté client et côté serveur correspondent.  
En cas de succès, le numéro de version est automatiquement incrémenté de 1. Cela peut être configuré avec`@DynamoDbVersionAttribute(incrementBy = X)`.

**`deleteItem`**  
L'`DynamoDbVersionAttribute`annotation n'a aucun effet. Vous devez ajouter une expression de condition manuellement lorsque vous supprimez un élément.  
L'exemple suivant ajoute une expression conditionnelle pour garantir que l'élément supprimé est bien celui qui a été lu. Dans l'exemple suivant, `recordVersion` l'attribut du bean est annoté avec`@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`: Cette méthode a le même comportement que`putItem`.
+ `addUpdateItem`: Cette méthode a le même comportement que`updateItem`.
+ `addDeleteItem`: Cette méthode a le même comportement que`deleteItem`.

**`batchWriteItem`**  
+ `addPutItem`: Cette méthode a le même comportement que`putItem`.
+ `addDeleteItem`: Cette méthode a le même comportement que`deleteItem`.

**Note**  
Les tables globales DynamoDB utilisent [une réconciliation « le dernier rédacteur gagne » entre les](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/V2globaltables_HowItWorks.html#V2globaltables_HowItWorks.consistency-modes) mises à jour simultanées, DynamoDB faisant de son mieux pour déterminer le dernier rédacteur. Si vous utilisez des tables globales, cette règle du « dernier rédacteur gagne » signifie que les stratégies de verrouillage risquent de ne pas fonctionner comme prévu, car toutes les répliques finiront par converger en fonction de la dernière écriture déterminée par DynamoDB. 

#### Comment désactiver
<a name="ddb-en-client-extensions-VRE-how-to-disable"></a>

Pour désactiver le verrouillage optimiste, n'utilisez pas l'`@DynamoDbVersionAttribute`annotation.

### Implémentez des compteurs avec le `AtomicCounterExtension`
<a name="ddb-en-client-extensions-ACE"></a>

L'`AtomicCounterExtension`extension incrémente un attribut numérique balisé chaque fois qu'un enregistrement est écrit dans la base de données. Vous pouvez spécifier des valeurs de départ et d'incrémentation. Si aucune valeur n'est spécifiée, la valeur de départ est définie sur 0 et la valeur de l'attribut augmente de 1.

#### Configuration
<a name="ddb-en-client-extensions-ACE-conf"></a>

Pour spécifier quel attribut est un compteur, balisez un attribut de type `Long` dans le schéma du tableau.

L'extrait suivant montre l'utilisation des valeurs de début et d'incrément par défaut pour l'attribut. `counter`

```
    @DynamoDbAtomicCounter
    public Long getCounter() {...};
    public void setCounter(Long counter) {...};
```

L'approche du schéma de table statique est illustrée dans l'extrait suivant. L'extension du compteur atomique utilise une valeur de départ de 10 et augmente la valeur de 5 à chaque fois que l'enregistrement est écrit.

```
    .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))
```

### Ajoutez des horodatages avec le `AutoGeneratedTimestampRecordExtension`
<a name="ddb-en-client-extensions-AGTE"></a>

L'`AutoGeneratedTimestampRecordExtension`extension met automatiquement à jour les attributs de type balisés `[Instant](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html)` avec un horodatage actuel chaque fois que l'élément est écrit avec succès dans la base de données. Cette extension n'est pas chargée par défaut.

#### Configuration
<a name="ddb-en-client-extensions-AGTE-conf"></a>

Pour spécifier l'attribut à mettre à jour avec l'horodatage actuel, balisez-le dans le `Instant` schéma de la table.

L'`lastUpdate`attribut est la cible du comportement de l'extension dans l'extrait suivant. Notez l'exigence selon laquelle l'attribut doit être un `Instant` type.

```
    @DynamoDbAutoGeneratedTimestampAttribute
    public Instant getLastUpdate() {...}
    public void setLastUpdate(Instant lastUpdate) {...}
```

L'approche équivalente du schéma de table statique est illustrée dans l'extrait suivant.

```
     .addAttribute(Instant.class, a -> a.name("lastUpdate")
                                        .getter(Customer::getLastUpdate)
                                        .setter(Customer::setLastUpdate)
                                        // Applying the 'autoGeneratedTimestamp' tag to the attribute.
                                        .tags(AutoGeneratedTimestampRecordExtension.AttributeTags.autoGeneratedTimestampAttribute())
```

### Générez un UUID avec le AutoGeneratedUuidExtension
<a name="ddb-en-client-extensions-AGUE"></a>

L'`AutoGeneratedUuidExtension`extension génère un UUID (identifiant unique universel) unique pour un attribut lorsqu'un nouvel enregistrement est écrit dans la base de données. Utilise la méthode Java JDK [UUID.randomUUID ()](https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html#randomUUID--) et s'applique aux attributs de type. `java.lang.String` Cette extension n'est pas chargée par défaut.

#### Configuration
<a name="ddb-en-client-extensions-AGUE-conf"></a>

L'`uniqueId`attribut est la cible du comportement de l'extension dans l'extrait suivant.

```
    @AutoGeneratedUuidExtension
    public String getUniqueId() {...}
    public void setUniqueId(String uniqueId) {...}
```

L'approche équivalente du schéma de table statique est illustrée dans l'extrait suivant.

```
     .addAttribute(String.class, a -> a.name("uniqueId")
                                        .getter(Customer::getUniqueId)
                                        .setter(Customer::setUniqueId)
                                        // Applying the 'autoGeneratedUuid' tag to the attribute.
                                        .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute())
```

Si vous souhaitez que l'extension renseigne l'UUID uniquement pour les `putItem` méthodes et non pour les `updateItem` méthodes, ajoutez l'annotation du [comportement de mise à jour](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html) comme indiqué dans l'extrait suivant.

```
    @AutoGeneratedUuidExtension
    @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)
    public String getUniqueId() {...}
    public void setUniqueId(String uniqueId) {...}
```

Si vous utilisez l'approche du schéma de table statique, utilisez le code équivalent suivant.

```
     .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))
```

# Exemple d'extension personnalisée
<a name="ddb-en-client-extensions-custom"></a>

Vous pouvez créer des extensions personnalisées en implémentant l'`DynamoDbEnhancedClientExtension`interface. La classe d'extension personnalisée suivante montre une `beforeWrite()` méthode qui utilise une expression de mise à jour pour définir un `registrationDate` attribut si l'élément de la base de données n'en possède pas déjà un.

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

# Utiliser l'API client améliorée DynamoDB de manière asynchrone
<a name="ddb-en-client-async"></a>

Si votre application nécessite des appels asynchrones non bloquants à DynamoDB, vous pouvez utiliser le. [DynamoDbEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html) Elle est similaire à l'implémentation synchrone, mais avec les principales différences suivantes :

1. Lorsque vous créez le`DynamoDbEnhancedAsyncClient`, vous devez fournir la version asynchrone du client standard`DynamoDbAsyncClient`, comme indiqué dans l'extrait de code suivant.

   ```
    DynamoDbEnhancedAsyncClient enhancedClient = 
        DynamoDbEnhancedAsyncClient.builder()
                                   .dynamoDbClient(dynamoDbAsyncClient)
                                   .build();
   ```

1. Les méthodes qui renvoient un seul objet de données renvoient une partie `CompletableFuture` du résultat au lieu du seul résultat. Votre application peut ensuite effectuer d'autres travaux sans avoir à bloquer le résultat. L'extrait suivant montre la méthode asynchrone`getItem()`. 

   ```
   CompletableFuture<Customer> result = customerDynamoDbTable.getItem(customer);
   // Perform other work here.
   return result.join();   // Now block and wait for the result.
   ```

1. Les méthodes qui renvoient des listes de résultats paginées renvoient un [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)au lieu d'un [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)que le synchrone `DynamoDbEnhanceClient` renvoie pour les mêmes méthodes. Votre application peut ensuite abonner un gestionnaire à cet éditeur pour traiter les résultats de manière asynchrone sans avoir à les bloquer.

   ```
   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.
   ```

   Pour un exemple plus complet d'utilisation du`SdkPublisher API`, consultez [l'exemple présenté](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-scan-async) dans la section de ce guide consacrée à la `scan()` méthode asynchrone.

# Annotations de classes de données
<a name="ddb-en-client-anno-index"></a>

Le tableau suivant répertorie les annotations qui peuvent être utilisées sur les classes de données et fournit des liens vers des informations et des exemples contenus dans ce guide. Le tableau est trié par ordre alphabétique croissant par nom d'annotation.


**Annotations de classes de données utilisées dans ce guide**  

| Nom de l'annotation | L'annotation s'applique à 1 | Ce qu'il fait | Où cela est indiqué dans ce guide | 
| --- | --- | --- | --- | 
| DynamoDbAtomicCounter | attribut 2 | Incrémente un attribut numérique balisé chaque fois qu'un enregistrement est écrit dans la base de données. | [Présentation et discussion.](ddb-en-client-extensions.md#ddb-en-client-extensions-ACE) | 
| DynamoDbAttribute | attribute | Définit ou renomme une propriété de bean mappée à un attribut de table DynamoDB. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbAutoGeneratedTimestampAttribute | attribute | Met à jour un attribut balisé avec un horodatage actuel chaque fois que l'élément est correctement écrit dans la base de données | [Présentation et discussion](ddb-en-client-extensions.md#ddb-en-client-extensions-AGTE). | 
| DynamoDbAutoGeneratedUuid | attribute | Générez un UUID (identifiant unique universel) unique pour un attribut lorsqu'un nouvel enregistrement est écrit dans la base de données. | [Présentation et discussion.](ddb-en-client-extensions.md#ddb-en-client-extensions-AGUE) | 
| DynamoDbBean | class | Marque une classe de données comme mappable à un schéma de table. | Première utilisation dans la [classe Customer](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) dans la section Commencer. Plusieurs utilisations apparaissent dans le guide. | 
| DynamoDbConvertedBy | attribute | Associe une personnalisation AttributeConverter à l'attribut annoté. | [Discussion initiale et exemple.](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-single) | 
| DynamoDbFlatten | attribute | Aplatit tous les attributs d'une classe de données DynamoDB distincte et les ajoute en tant qu'attributs de premier niveau à l'enregistrement lu et écrit dans la base de données.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnore | attribute |  Il en résulte que l'attribut reste non mappé.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnoreNulls | attribute | Empêche l'enregistrement des attributs nuls des DynamoDb objets imbriqués. | [Discussion et exemples.](ddb-en-client-adv-features-ignore-null.md) | 
| DynamoDbImmutable | class |  Marque une classe de données immuable comme mappable à un schéma de table.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPartitionKey | attribute |  Marque un attribut comme clé de partition principale (clé de hachage) de la DynamoDb table.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPreserveEmptyObject | attribute |  Spécifie que si aucune donnée n'est présente pour l'objet mappé à l'attribut annoté, l'objet doit être initialisé avec tous les champs nuls.  | [Discussion et exemples.](ddb-en-client-adv-features-empty.md) | 
| DynamoDbSecondaryPartitionKey | attribute |  Marque un attribut comme clé de partition pour un index secondaire global.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSecondarySortKey | attribute |  Marque un attribut comme clé de tri facultative pour un index secondaire global ou local.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSortKey | attribute |  Marque un attribut comme clé de tri primaire facultative (clé de plage).  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbUpdateBehavior | attribute |  Spécifie le comportement lorsque cet attribut est mis à jour dans le cadre d'une opération de « mise à jour » telle que UpdateItem.  | [Introduction et exemple.](ddb-en-client-adv-features-upd-behavior.md) | 
| DynamoDbVersionAttribute | attribute | Incrémente le numéro de version d'un article. | [Présentation et discussion.](ddb-en-client-extensions.md#ddb-en-client-extensions-VRE) | 

1 Vous pouvez appliquer des annotations au niveau de l'attribut au getter ou au setter, mais pas aux deux. Ce guide montre les annotations sur les getters.

2 Le terme `property` est normalement utilisé pour une valeur encapsulée dans une classe de JavaBean données. Toutefois, ce guide utilise ce terme à la `attribute` place, par souci de cohérence avec la terminologie utilisée par DynamoDB.