

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.

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