

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Lavora con DynamoDB
<a name="examples-dynamodb"></a>

[DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) è un servizio di database NoSQL completamente gestito che offre prestazioni veloci e prevedibili con una scalabilità perfetta. Questa sezione mostra come lavorare con DynamoDB utilizzando la versione 2.x. AWS SDK per Java 

## Scegli il tuo client DynamoDB
<a name="ddb-clients-overview"></a>

L'SDK offre due approcci principali per lavorare con DynamoDB:

Client di basso livello (`DynamoDbClient`)  
Fornisce accesso diretto alle operazioni di DynamoDB con il pieno controllo su richieste e risposte. Usa questo client quando hai bisogno di un controllo preciso o lavori con schemi dinamici.

Client avanzato () `DynamoDbEnhancedClient`  
Offre una programmazione orientata agli oggetti con mappatura automatica tra oggetti Java ed elementi DynamoDB. Fornisce inoltre funzionalità orientate ai documenti per lavorare con dati simili a JSON che non seguono uno schema fisso. Utilizzate questo client quando lavorate con modelli di dati ben definiti o dati di tipo documento.

## Configurazione dei client DynamoDB
<a name="ddb-configuration-setup"></a>

Prima di lavorare con DynamoDB, configura il client per prestazioni e affidabilità ottimali.

### Comprendere il comportamento di ripetizione dei tentativi di DynamoDB
<a name="ddb-retry-behavior"></a>

I client DynamoDB utilizzano un numero massimo di tentativi predefinito di 8, che è superiore a quello degli altri client. Servizio AWS Questo numero più elevato di tentativi aiuta a gestire la natura distribuita di DynamoDB e i limiti temporanei di capacità. Per ulteriori informazioni sulle strategie di ripetizione dei tentativi, consulta. [Configurare il comportamento dei tentativi in AWS SDK for Java 2.x](retry-strategy.md)

### Ottimizza le prestazioni con endpoint basati su account
<a name="ddb-account-based-endpoints-v2"></a>

DynamoDB [AWS offre endpoint basati su account](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.SDKOverview.html#Programming.SDKs.endpoints) che migliorano le prestazioni utilizzando l'ID dell'account per semplificare AWS il routing delle richieste. 

Per utilizzare questa funzionalità, è necessaria la versione 2.28.4 o successiva di. AWS SDK for Java 2.x Puoi trovare l'ultima versione nel repository centrale di [Maven](https://central.sonatype.com/artifact/software.amazon.awssdk/bom/versions). Le versioni SDK supportate utilizzano automaticamente i nuovi endpoint.

Per disattivare il routing basato sull'account, scegli una di queste opzioni:
+ Configurare un client `AccountIdEndpointMode` di servizio DynamoDB con set to. `DISABLED`
+ Imposta una variabile di ambiente.
+ Imposta una proprietà del sistema JVM.
+ Aggiorna l'impostazione del file di AWS configurazione condiviso.

L'esempio seguente mostra come disabilitare il routing basato sull'account configurando un client di servizio DynamoDB:

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

Per ulteriori informazioni sulle altre opzioni di configurazione, consulta Endpoint [basati su account](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html) nella and Tools Reference Guide. AWS SDKs 

## Cosa viene trattato in questo argomento
<a name="ddb-topics-overview"></a>

Le seguenti sezioni mostrano come lavorare con DynamoDB:
+ [Lavora con le tabelle in DynamoDB](examples-dynamodb-tables.md)- Creare, descrivere, aggiornare ed eliminare tabelle
+ [Lavora con gli elementi in DynamoDB](examples-dynamodb-items.md)- Aggiungi, recupera e aggiorna singoli elementi
+ [Mappa gli oggetti Java sugli elementi DynamoDB con AWS SDK for Java 2.x](dynamodb-enhanced-client.md)- Utilizza la mappatura degli oggetti e i dati orientati ai documenti con Enhanced Client

Per ulteriori esempi di codice DynamoDB, consulta Esempi di codice [DynamoDB nella Code Examples Library](java_dynamodb_code_examples.md). AWS 

# Lavora con le tabelle in DynamoDB
<a name="examples-dynamodb-tables"></a>

Le tabelle sono i contenitori per tutti gli elementi di un DynamoDB database. Prima di poter aggiungere o rimuovere dati da DynamoDB, è necessario creare una tabella.

Per ogni tabella, devi definire:
+ Un *nome* di tabella unico per il tuo account e la tua regione.
+ Una *chiave primaria* per la quale ogni valore deve essere univoco; due item nella tabella non possono avere lo stesso valore della chiave primaria.

  La chiave primaria può essere *semplice*, costituita da una singola chiave di partizione (HASH), o *composita*, costituita da una chiave di partizione e una di ordinamento (RANGE).

  A ogni valore chiave è associato un *tipo di dati*, enumerato dalla classe. [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) Il valore della chiave può essere binario (B), numerico (N) o una stringa (S). Per ulteriori informazioni, consulta [Regole di denominazione e tipi di dati](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) nella Guida per gli sviluppatori. Amazon DynamoDB 
+  Il *throughput assegnato* è costituito da valori che definiscono il numero di unità di capacità di lettura/scrittura prenotati per la tabella.
**Nota**  
 [Amazon DynamoDB i prezzi](https://aws.amazon.com/dynamodb/pricing/) si basano sui valori di throughput assegnati che imposti sulle tabelle, quindi prenota solo la capacità che ritieni necessaria per la tabella.

  Il throughput assegnato per una tabella può essere modificato in qualsiasi momento, pertanto puoi modificare la capacità in base alle esigenze.

## Creare una tabella
<a name="dynamodb-create-table"></a>

Usa il `DynamoDbClient’s` `createTable` metodo per creare una nuova DynamoDB tabella. È necessario costruire gli attributi della tabella e uno schema della tabella, entrambi utilizzati per identificare la chiave primaria della tabella. Inoltre, occorre fornire i valori del throughput assegnato iniziali e un nome della tabella.

**Nota**  
Se esiste già una tabella con il nome scelto, `[DynamoDbException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/DynamoDbException.html)` viene generata a.

### Creazione di una tabella con una chiave primaria semplice
<a name="dynamodb-create-table-simple"></a>

Questo codice crea una tabella con un attributo che è la chiave primaria semplice della tabella. l'esempio utilizza `[AttributeDefinition](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeDefinition.html)` e `[KeySchemaElement](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/KeySchemaElement.html)` oggetti per. [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)

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTable.java) su. GitHub

### Creazione di una tabella con una chiave primaria composita
<a name="dynamodb-create-table-composite"></a>

L'esempio seguente crea una tabella con due attributi. Entrambi gli attributi vengono utilizzati per la chiave primaria composita.

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTableCompositeKey.java) su GitHub.

## Elencare tabelle
<a name="dynamodb-list-tables"></a>

È possibile elencare le tabelle in una particolare regione chiamando il `DynamoDbClient’s` `listTables` metodo.

**Nota**  
Se la tabella denominata non esiste per il tuo account e la tua regione, [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)viene generata a.

 **Importazioni** 

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

 **Codice** 

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

Per impostazione predefinita, vengono restituite fino a 100 tabelle per chiamata: da utilizzare `lastEvaluatedTableName` sull'[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)oggetto restituito per ottenere l'ultima tabella valutata. Puoi utilizzare questo valore per avviare la visualizzazione dell'elenco dopo l'ultimo valore restituito dalla visualizzazione dell'elenco precedente.

Vedi l'esempio [completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/ListTables.java) su. GitHub

## Descrizione di (recupero delle informazioni su) una tabella
<a name="dynamodb-describe-table"></a>

Utilizzate il `DynamoDbClient’s` `describeTable` metodo per ottenere informazioni su una tabella.

**Nota**  
Se la tabella denominata non esiste per il tuo account e la tua regione, [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)viene generata a.

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DescribeTable.java) su. GitHub

## Modifica (aggiornamento) di una tabella
<a name="dynamodb-update-table"></a>

È possibile modificare i valori di throughput assegnati alla tabella in qualsiasi momento chiamando il `DynamoDbClient’s` `updateTable` metodo.

**Nota**  
Se la tabella denominata non esiste per il tuo account e la tua regione, [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)viene generata a.

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateTable.java) su. GitHub

## Eliminazione di una tabella
<a name="dynamodb-delete-table"></a>

Per eliminare una tabella, chiama `DynamoDbClient’s` `deleteTable` method e fornisci il nome della tabella.

**Nota**  
Se la tabella denominata non esiste per il tuo account e la tua regione, [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)viene generata a.

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteTable.java) su. GitHub

## Ulteriori informazioni
<a name="more-information"></a>
+  [Linee guida per l'utilizzo delle tabelle](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html) nella Guida per Amazon DynamoDB gli sviluppatori
+  [Utilizzo delle tabelle DynamoDB nella](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html) Guida per gli Amazon DynamoDB sviluppatori

# Lavora con gli elementi in DynamoDB
<a name="examples-dynamodb-items"></a>

*In DynamoDB, un elemento è una raccolta di *attributi*, ognuno dei quali ha un *nome* e un valore.* Un valore attributo può essere un tipo scalare, set o documento. Per ulteriori informazioni, consulta [Regole di denominazione e tipi di dati](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) nella Guida per gli Amazon DynamoDB sviluppatori.

## Recuperare (ottenere) un item da una tabella
<a name="dynamodb-get-item"></a>

Chiama il `getItem` metodo DynamoDbClient's e passagli un [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html)oggetto con il nome della tabella e il valore della chiave primaria dell'elemento desiderato. Restituisce un [GetItemResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemResponse.html)oggetto con tutti gli attributi di quell'elemento. Puoi specificare una o più [espressioni di proiezione](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html) in `GetItemRequest` per recuperare attributi specifici.

È possibile utilizzare il `item()` metodo dell'`GetItemResponse`oggetto restituito per recuperare una [mappa](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) di coppie chiave (String [AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html)) e valore () associate all'elemento.

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/GetItem.java) su. GitHub

## Recupero (Get) di una voce da una tabella utilizzando il client asincrono
<a name="id1ddb"></a>

Invocate il `getItem` metodo di DynamoDbAsyncClient e passategli un [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html)oggetto con il nome della tabella e il valore della chiave primaria dell'elemento desiderato.

È possibile restituire un'istanza di [raccolta](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Collection.html) con tutti gli attributi per tale voce (fare riferimento all'esempio seguente).

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/DynamoDBAsyncGetItem.java) su. GitHub

## Aggiunta di un nuovo item a una tabella
<a name="dynamodb-add-item"></a>

Creare una [mappa](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) di coppie chiave-valore che rappresentino gli attributi della voce. Queste devono includere valori per i campi chiave primaria della tabella. Se l'elemento identificato dalla chiave primaria esiste già, i relativi campi vengono *aggiornati* dalla richiesta.

**Nota**  
Se la tabella denominata non esiste per il tuo account e la tua regione, [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)viene generata a.

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/PutItem.java) su. GitHub

## Aggiornamento di un item esistente in una tabella
<a name="dynamodb-update-item"></a>

È possibile aggiornare un attributo per una voce che esiste già in una tabella utilizzando il metodo `updateItem` di DynamoDbClient, fornendo un nome di tabella, un valore chiave primaria e una mappa di campi da aggiornare.

**Nota**  
Se la tabella denominata non esiste per il tuo account e la tua regione, o se l'elemento identificato dalla chiave primaria che hai passato non esiste, [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)viene generato a.

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateItem.java) su. GitHub

## Aggiornamento di una voce (item) esistente in una tabella
<a name="dynamodb-delete-item"></a>

È possibile eliminare un elemento esistente in una tabella utilizzando il `deleteItem` metodo DynamoDbClient's e fornendo un nome di tabella oltre al valore della chiave primaria.

**Nota**  
Se la tabella denominata non esiste per il tuo account e la tua regione, o se l'elemento identificato dalla chiave primaria che hai passato non esiste, [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)viene generato un.

 **Importazioni** 

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

 **Codice** 

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

Vedi l'[esempio completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteItem.java) su. GitHub

## Ulteriori informazioni
<a name="more-information"></a>
+  [Linee guida per l'utilizzo degli elementi](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/best-practices.html) nella Guida per gli Amazon DynamoDB sviluppatori
+  [Utilizzo degli elementi contenuti DynamoDB nella](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/WorkingWithItems.html) Guida per gli Amazon DynamoDB sviluppatori

# Mappa gli oggetti Java sugli elementi DynamoDB con 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) è una libreria di alto livello che è il successore della classe di SDK for `DynamoDBMapper` Java v1.x. Offre un modo semplice per mappare le classi lato client alle tabelle DynamoDB. Le relazioni tra le tabelle e le classi di dati corrispondenti vengono definite nel codice. Dopo aver definito queste relazioni, è possibile eseguire in modo intuitivo varie operazioni di creazione, lettura, aggiornamento o eliminazione (CRUD) su tabelle o elementi in DynamoDB.

L'API Enhanced Client di DynamoDB include anche [l'API Enhanced Document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) che consente di lavorare con elementi di tipo documento che non seguono uno schema definito. 

**Topics**
+ [Inizia a usare l'API DynamoDB Enhanced Client](ddb-en-client-getting-started.md)
+ [Scopri le basi dell'API DynamoDB Enhanced Client](ddb-en-client-use.md)
+ [Usa funzionalità di mappatura avanzate](ddb-en-client-adv-features.md)
+ [Lavora con documenti JSON con l'API Enhanced Document per DynamoDB](ddb-en-client-doc-api.md)
+ [Usa le estensioni per personalizzare le operazioni di DynamoDB Enhanced Client](ddb-en-client-extensions.md)
+ [Usa l'API DynamoDB Enhanced Client in modo asincrono](ddb-en-client-async.md)
+ [Annotazioni di classi di dati](ddb-en-client-anno-index.md)

# Inizia a usare l'API DynamoDB Enhanced Client
<a name="ddb-en-client-getting-started"></a>

Il seguente tutorial presenta le nozioni di base necessarie per lavorare con l'API DynamoDB Enhanced Client.

## Aggiungi dipendenze
<a name="ddb-en-client-gs-dep"></a>

Per iniziare a utilizzare l'API DynamoDB Enhanced Client nel tuo progetto, aggiungi una dipendenza dall'artefatto Maven. `dynamodb-enhanced` Questo è illustrato negli esempi seguenti. 

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

Esegui una ricerca nell'archivio centrale di Maven per la [versione più recente](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) e sostituiscila *<VERSION>* con questo valore.

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

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

Esegui una ricerca nell'archivio centrale di Maven per la [versione più recente](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) e sostituiscila con questo valore. *<VERSION>*

------

# Genera un `TableSchema` da una classe di dati
<a name="ddb-en-client-gs-tableschema"></a>

A `[TableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableSchema.html)` consente al client avanzato di mappare i valori degli attributi DynamoDB da e verso le classi lato client. In questo tutorial, imparerai a conoscere `TableSchema` i file derivati da una classe di dati statici e generati dal codice utilizzando un builder.

## Usa una classe di dati annotata
<a name="ddb-en-client-gs-tableschema-anno-bean"></a>

L'SDK for Java 2.x include [un set di](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/package-summary.html) annotazioni che è possibile utilizzare con una classe di dati per generare `TableSchema` rapidamente un file per mappare le classi alle tabelle.

[Inizia creando una classe di dati conforme alle specifiche. JavaBean ](https://download.oracle.com/otn-pub/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/beans.101.pdf) La specifica richiede che una classe disponga di un costruttore pubblico senza argomenti e che disponga di getter e setter per ogni attributo della classe. Includi un'annotazione a livello di classe per indicare che la classe di dati è una. `DynamoDbBean` Inoltre, includi almeno un'`DynamoDbPartitionKey`annotazione sul getter o setter per l'attributo chiave primaria. 

È possibile applicare [annotazioni a livello di attributo a](ddb-en-client-anno-index.md) getter o setter, ma non a entrambi.

**Nota**  
Il termine `property` viene normalmente utilizzato per un valore incapsulato in un. JavaBean Tuttavia, questa guida utilizza `attribute` invece il termine, per coerenza con la terminologia utilizzata da DynamoDB.

La `Customer` classe seguente mostra le annotazioni che collegano la definizione della classe a una tabella 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 + "]";
    }
}
```

Dopo aver creato una classe di dati annotata, usatela per creare la`TableSchema`, come mostrato nel seguente frammento.

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

A `TableSchema` è progettato per essere statico e immutabile. Di solito puoi istanziarlo al momento del caricamento della classe.

Il metodo static `TableSchema.fromBean()` factory analizza il bean per generare la mappatura degli attributi (proprietà) delle classi di dati da e verso gli attributi DynamoDB.

Per un esempio di utilizzo di un modello di dati composto da diverse classi di dati, consultate la classe nella `Person` sezione. [Lavora con attributi che sono bean, mappe, elenchi e set](ddb-en-client-adv-features-nested.md)

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

Puoi saltare il costo dell'introspezione dei bean se definisci lo schema della tabella nel codice. Se codifichi lo schema, la tua classe non ha bisogno di seguire gli standard di JavaBean denominazione né di essere annotata. L'esempio seguente utilizza un generatore ed è equivalente all'esempio di `Customer` classe che utilizza le annotazioni.

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

# Crea un client avanzato e `DynamoDbTable`
<a name="ddb-en-client-getting-started-dynamodbTable"></a>

## Crea un client avanzato
<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, o la sua controparte asincrona [DynamoDbEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html), è il punto di partenza per lavorare con l'API DynamoDB Enhanced Client.

Il client avanzato richiede uno standard per eseguire il lavoro. `[DynamoDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html)` L'API offre due modi per creare un'`DynamoDbEnhancedClient`istanza. La prima opzione, mostrata nel frammento seguente, crea uno standard `DynamoDbClient` con le impostazioni predefinite raccolte dalle impostazioni di configurazione.

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

Se desideri configurare il client standard sottostante, puoi fornirlo al metodo builder del client avanzato, come mostrato nel seguente frammento.

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

## Creazione di un'Istanza `DynamoDbTable`
<a name="ddb-en-client-getting-started-dynamodbTable-table"></a>

Pensate 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)come alla rappresentazione lato client di una tabella DynamoDB che utilizza la funzionalità di mappatura fornita da a. `TableSchema` La `DynamoDbTable` classe fornisce metodi per le operazioni CRUD che consentono di interagire con una singola tabella DynamoDB.

`DynamoDbTable<T>`è una classe generica che accetta un argomento di tipo singolo, sia che si tratti di una classe personalizzata o di un argomento `EnhancedDocument` quando si lavora con elementi di tipo documento. Questo tipo di argomento stabilisce la relazione tra la classe utilizzata e la singola tabella DynamoDB.

Utilizzate il metodo `table()` factory di `DynamoDbEnhancedClient` per creare un'`DynamoDbTable`istanza, come mostrato nel frammento seguente.

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

`DynamoDbTable`le istanze sono candidate per essere utilizzate singleton perché sono immutabili e possono essere utilizzate in tutta l'applicazione.

Il codice ora ha una rappresentazione in memoria di una tabella DynamoDB che può funzionare con le istanze. `Customer` La tabella DynamoDB effettiva potrebbe esistere o meno. Se la tabella denominata esiste `Customer` già, puoi iniziare a eseguire operazioni CRUD su di essa. Se non esiste, utilizzate l'`DynamoDbTable`istanza per creare la tabella come illustrato nella sezione successiva.

# Se necessario, creare una tabella DynamoDB
<a name="ddb-en-client-gs-ddbtable"></a>

Dopo aver creato un'`DynamoDbTable`istanza, utilizzala per creare una *sola volta* una tabella in DynamoDB.

## Crea un codice di esempio per la tabella
<a name="ddb-en-client-gs-ddbtable-createex"></a>

L'esempio seguente crea una tabella DynamoDB basata sulla `Customer` classe di dati. 

Questo esempio crea una tabella DynamoDB con il `Customer` nome, identico al nome della classe, ma il nome della tabella può essere qualcos'altro. Qualunque sia il nome dato alla tabella, è necessario utilizzare questo nome in altre applicazioni per lavorare con la tabella. Fornite questo nome al `table()` metodo ogni volta che create un altro `DynamoDbTable` oggetto per lavorare con la tabella DynamoDB sottostante.

[Il parametro Java lambda`builder`, passato al `createTable` metodo consente di personalizzare la tabella.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html) In questo esempio, viene configurato il [throughput assegnato](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.ProvisionedThroughput.Manual). Se desideri utilizzare le impostazioni predefinite quando crei una tabella, salta il generatore, come mostrato nel frammento seguente.

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

Quando vengono utilizzate le impostazioni predefinite, i valori per il throughput assegnato non vengono impostati. [Al contrario, la modalità di fatturazione per la tabella è impostata su richiesta.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.OnDemand)

L'esempio utilizza anche un `[DynamoDbWaiter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/waiters/DynamoDbWaiter.html)` prima di tentare di stampare il nome della tabella ricevuto nella risposta. La creazione di una tabella richiede del tempo. Pertanto, l'utilizzo di un cameriere significa che non è necessario scrivere una logica che interroghi il servizio DynamoDB per verificare se la tabella esiste prima di utilizzarla.

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

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

**Nota**  
I nomi degli attributi di una tabella DynamoDB iniziano con una lettera minuscola quando la tabella viene generata da una classe di dati. Se desideri che il nome dell'attributo della tabella inizi con una lettera maiuscola, usa l'[`@DynamoDbAttribute(NAME)`annotazione](ddb-en-client-adv-features-inex-attr.md) e fornisci il nome che desideri come parametro.

# Esegui operazioni
<a name="ddb-en-client-gs-use"></a>

Dopo aver creato la tabella, utilizzate l'`DynamoDbTable`istanza per eseguire operazioni sulla tabella DynamoDB. 

Nell'esempio seguente, un singleton `DynamoDbTable<Customer>` viene passato come parametro insieme a un'istanza della [classe di `Customer` dati](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) per aggiungere un nuovo elemento alla tabella.

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

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

Prima di inviare l'`customer`oggetto al servizio DynamoDB, registrate l'output del metodo `toString()` dell'oggetto per confrontarlo con quello inviato dal client avanzato.

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

La registrazione a livello di cavo mostra il payload della richiesta generata. Il client avanzato ha generato la rappresentazione di basso livello dalla classe di dati. L'`regDate`attributo, che è un `Instant` tipo in Java, è rappresentato come una stringa DynamoDB.

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

# Lavora con una tabella esistente
<a name="ddb-en-client-gs-existingtable"></a>

La sezione precedente mostrava come creare una tabella DynamoDB a partire da una classe di dati Java. Se disponi già di una tabella esistente e desideri utilizzare le funzionalità del client avanzato, puoi creare una classe di dati Java per lavorare con la tabella. È necessario esaminare la tabella DynamoDB e aggiungere le annotazioni necessarie alla classe di dati. 

Prima di lavorare con una tabella esistente, chiamate il metodo. `DynamoDbEnhanced.table()` Ciò è stato fatto nell'esempio precedente con la seguente dichiarazione.

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

Dopo la restituzione dell'`DynamoDbTable`istanza, potete iniziare subito a lavorare con la tabella sottostante. Non è necessario ricreare la tabella chiamando il `DynamoDbTable.createTable()` metodo.

L'esempio seguente lo dimostra recuperando immediatamente un'`Customer`istanza dalla tabella 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());
```

**Importante**  
Il nome della tabella utilizzato nel `table()` metodo deve corrispondere al nome della tabella DynamoDB esistente.

# Scopri le basi dell'API DynamoDB Enhanced Client
<a name="ddb-en-client-use"></a>

[Questo argomento illustra le funzionalità di base dell'API DynamoDB Enhanced Client e la confronta con l'API client DynamoDB standard.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html)

Se non conosci l'API DynamoDB Enhanced Client, ti consigliamo di seguire il tutorial [introduttivo per familiarizzare con le](ddb-en-client-getting-started.md) classi fondamentali.

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

Le tabelle DynamoDB memorizzano gli elementi. A seconda del caso d'uso, gli elementi sul lato Java possono assumere la forma di dati strutturati staticamente o di strutture create dinamicamente. 

Se il tuo caso d'uso richiede elementi con un set coerente di attributi, usa [classi annotate](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean) o usa un [builder](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-builder) per generare i tipi statici appropriati. `TableSchema` 

In alternativa, se devi archiviare elementi costituiti da strutture diverse, crea un. `DocumentTableSchema` `DocumentTableSchema`fa parte dell'[API Enhanced Document](ddb-en-client-doc-api.md) e richiede solo una chiave primaria tipizzata staticamente e funziona con le `EnhancedDocument` istanze per contenere gli elementi di dati. [L'API Enhanced Document è trattata in un altro argomento.](ddb-en-client-doc-api.md)

## Tipi di attributi per le classi del modello di dati
<a name="ddb-en-client-use-types"></a>

Sebbene DynamoDB [supporti un numero limitato di tipi di attributi rispetto al rich type system di](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) Java, l'API DynamoDB Enhanced Client fornisce meccanismi per convertire i membri di una classe Java da e verso i tipi di attributi DynamoDB.

I tipi di attributi (proprietà) delle classi di dati Java devono essere tipi di oggetti, non primitivi. Ad esempio, utilizzate `Long` sempre tipi di dati `Integer` oggetto, non `long` e `int` primitivi.

[Per impostazione predefinita, l'API DynamoDB Enhanced Client supporta convertitori di attributi per un gran numero di tipi, [come Integer[,](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) String](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html) e Instant. [BigDecimal](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/BigDecimalAttributeConverter.html)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/InstantAsStringAttributeConverter.html) L'elenco viene visualizzato nelle [classi di implementazione note](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html) dell'interfaccia. AttributeConverter L'elenco include molti tipi e raccolte come mappe, elenchi e set.

Per memorizzare i dati per un tipo di attributo che non è supportato di default o non è conforme alla JavaBean convenzione, puoi scrivere un'`AttributeConverter`implementazione personalizzata per eseguire la conversione. Vedi la sezione sulla conversione degli attributi per un [esempio](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example).

Per memorizzare i dati per un tipo di attributo la cui classe è conforme alla specifica Java beans (o una [classe di dati immutabile](ddb-en-client-use-immut.md)), puoi adottare due approcci. 
+ Se avete accesso al file sorgente, potete annotare la classe con `@DynamoDbBean` (o). `@DynamoDbImmutable` La sezione che illustra gli attributi annidati mostra [esempi](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-anno) di utilizzo di classi annotate.
+ Se non hai accesso al file sorgente della classe di JavaBean dati per l'attributo (o non vuoi annotare il file sorgente di una classe a cui hai accesso), puoi usare l'approccio builder. Questo crea uno schema tabellare senza definire le chiavi. Quindi, puoi annidare questo schema di tabella all'interno di un altro schema di tabella per eseguire la mappatura. La sezione degli attributi nidificati contiene un [esempio](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-builder) che mostra l'uso di schemi nidificati.

### Valori nulli
<a name="ddb-en-client-use-types-nulls"></a>

Quando si utilizza il `putItem` metodo, il client avanzato non include gli attributi con valori nulli di un oggetto dati mappato nella richiesta a DynamoDB.

Il comportamento predefinito dell'SDK per `updateItem` le richieste rimuove gli attributi dall'elemento in DynamoDB che sono impostati su null nell'oggetto inviato nel metodo. `updateItem` Se intendi aggiornare alcuni valori degli attributi e mantenere invariati gli altri, hai due opzioni.
+ Recuperate l'elemento (utilizzando`getItem`) prima di apportare modifiche ai valori. Utilizzando questo approccio, l'SDK invia tutti i valori vecchi e aggiornati a DynamoDB.
+ Usa `[IgnoreNullsMode](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html).SCALAR_ONLY` o `IgnoreNullsMode.MAPS_ONLY` quando crei la richiesta per aggiornare l'elemento. Entrambe le modalità ignorano le proprietà con valori nulli nell'oggetto che rappresentano gli attributi scalari in DynamoDB. L'[Aggiorna gli elementi che contengono tipi complessi](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-updates)argomento di questa guida contiene ulteriori informazioni sui `IgnoreNullsMode` valori e su come lavorare con tipi complessi.

L'esempio seguente illustra `ignoreNullsMode()` il `updateItem()` metodo.

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

## Metodi di base di DynamoDB Enhanced Client
<a name="ddb-en-client-use-basic-ops"></a>

I metodi di base del client avanzato si associano alle operazioni del servizio DynamoDB da cui prendono il nome. Gli esempi seguenti mostrano la variante più semplice di ciascun metodo. È possibile personalizzare ogni metodo passando un oggetto di richiesta avanzato. Gli oggetti di richiesta avanzati offrono la maggior parte delle funzionalità disponibili nel client DynamoDB standard. Sono completamente documentati nell'API Reference. AWS SDK for Java 2.x 

L'esempio utilizza quanto [Classe `Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) mostrato in precedenza.

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

## Confronta DynamoDB Enhanced Client con il client DynamoDB standard
<a name="ddb-en-client-use-compare"></a>

[Entrambi i APIs client DynamoDB, standard [e](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html) avanzato, consentono di lavorare con le tabelle DynamoDB per eseguire operazioni CRUD (creazione, lettura, aggiornamento ed eliminazione) a livello di dati.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html) La differenza tra i client sta nel modo in cui ciò viene realizzato. APIs Utilizzando il client standard, si lavora direttamente con attributi di dati di basso livello. L'API client avanzata utilizza classi Java familiari e si collega all'API di basso livello dietro le quinte.

Sebbene entrambi i client APIs supportino operazioni a livello di dati, il client DynamoDB standard supporta anche operazioni a livello di risorsa. Le operazioni a livello di risorsa gestiscono il database, come la creazione di backup, l'elenco delle tabelle e l'aggiornamento delle tabelle. L'API client avanzata supporta un numero selezionato di operazioni a livello di risorsa come la creazione, la descrizione e l'eliminazione di tabelle.

Per illustrare i diversi approcci utilizzati dai due client APIs, i seguenti esempi di codice mostrano la creazione della stessa `ProductCatalog` tabella utilizzando il client standard e il client avanzato.

### Confronto: crea una tabella utilizzando il 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))
);
```

### Confronta: crea una tabella utilizzando il DynamoDB Enhanced Client
<a name="ddb-en-client-use-compare-cs2"></a>

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

Il client avanzato utilizza la seguente classe di dati annotati. Il DynamoDB Enhanced Client mappa i tipi di dati Java ai tipi di dati DynamoDB per un codice meno dettagliato e più facile da seguire. `ProductCatalog`è un esempio di utilizzo di una classe immutabile con DynamoDB Enhanced Client. [L'uso delle classi Immutabili per le classi di dati mappate viene discusso più avanti in questo argomento.](ddb-en-client-use-immut.md)

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

I due esempi di codice seguenti di scrittura in batch illustrano la verbosità e la mancanza di sicurezza dei tipi quando si utilizza il client standard anziché il client avanzato.

### Confronto: Scrittura in batch utilizzando il 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());
    }
```

### Confronto: Scrittura in batch utilizzando il DynamoDB Enhanced Client
<a name="ddb-en-client-use-compare-cs5"></a>

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

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

# Lavora con classi di dati immutabili
<a name="ddb-en-client-use-immut"></a>

La funzionalità di mappatura dell'API DynamoDB Enhanced Client funziona con classi di dati immutabili. Una classe immutabile ha solo getter e richiede una classe builder che l’SDK utilizza per creare istanze della classe. Invece di utilizzare l'`@DynamoDbBean`annotazione come mostrato nella [classe Customer](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust), le classi immutabili utilizzano l'`@DynamoDbImmutable`annotazione, che accetta un parametro che indica la classe builder da utilizzare.

La classe seguente è una versione immutabile di. `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); }
    }
}
```

È necessario soddisfare i seguenti requisiti quando si annota una classe di dati con. `@DynamoDbImmutable`

1. Ogni metodo che non sostituisce `Object.class` e con cui non è stato annotato `@DynamoDbIgnore` deve essere un getter per un attributo della tabella DynamoDB.

1. Ogni getter deve avere un setter corrispondente con distinzione tra maiuscole e minuscole nella classe builder.

1. Deve essere soddisfatta solo una delle seguenti condizioni di costruzione.
   + La classe builder deve avere un costruttore pubblico predefinito.
   + La classe di dati deve avere un metodo statico pubblico denominato `builder()` che non accetta parametri e restituisce un'istanza della classe builder. Questa opzione è mostrata nella classe immutable`Customer`.

1.  La classe builder deve avere un metodo pubblico denominato `build()` che non accetta parametri e restituisce un'istanza della classe immutabile. 

Per crearne uno `TableSchema` per la tua classe immutabile, usa il `fromImmutableClass()` metodo on `TableSchema` come mostrato nel seguente frammento.

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

Proprio come è possibile creare una tabella DynamoDB da una classe mutabile, è possibile crearne una da una classe immutabile con *una* chiamata singola a of, come illustrato nel seguente esempio `DynamoDbTable` di `createTable()` snippet.

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

## Usa librerie di terze parti, come Lombok
<a name="ddb-en-client-use-immut-lombok"></a>

Le librerie di terze parti, come [Project Lombok](https://projectlombok.org/), aiutano a generare codice standard associato a oggetti immutabili. L'API DynamoDB Enhanced Client funziona con queste librerie purché le classi di dati seguano le convenzioni descritte in questa sezione. 

L'esempio seguente mostra la classe immutabile `CustomerImmutable` con annotazioni Lombok. Nota come la `onMethod` funzionalità di Lombok copia le annotazioni DynamoDB basate su attributi, ad esempio, sul codice generato. `@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;
}
```

# Usa espressioni e condizioni
<a name="ddb-en-client-expressions"></a>

[Le espressioni nell'API DynamoDB Enhanced Client sono rappresentazioni Java delle espressioni DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html)

L'API DynamoDB Enhanced Client utilizza tre tipi di espressioni:

[Expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)  
La `Expression` classe viene utilizzata quando si definiscono condizioni e filtri.

[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)  
Questo tipo di espressione rappresenta [le condizioni chiave per le](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions) operazioni di interrogazione.

[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)  
Questa classe consente di scrivere espressioni di [aggiornamento di DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html) ed è attualmente utilizzata nel framework di estensione quando si aggiorna un elemento.

## Anatomia delle espressioni
<a name="ddb-en-client-expressions-compoonents"></a>

Un'espressione è composta dai seguenti elementi:
+ Un'espressione stringa (obbligatoria). La stringa contiene un'espressione logica DynamoDB con nomi segnaposto per i nomi e i valori degli attributi.
+ Una mappa dei valori delle espressioni (in genere richiesta).
+ Una mappa dei nomi delle espressioni (opzionale).

Utilizzate un builder per generare un `Expression` oggetto che assuma la seguente forma generale.

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

`Expression`Di solito richiede una mappa di valori di espressione. La mappa fornisce i valori per i segnaposto nell'espressione stringa. La chiave della mappa è costituita dal nome del segnaposto preceduto da due punti (`:`) e il valore della mappa è un'istanza di. [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 dispone di metodi pratici per generare un'`AttributeValue`istanza da un valore letterale. In alternativa, è possibile utilizzare il `AttributeValue.Builder` per generare un'`AttributeValue`istanza.

Il seguente frammento mostra una mappa con due voci dopo la riga di commento 2. La stringa passata al `expression()` metodo, mostrata dopo la riga di commento 1, contiene i segnaposto che DynamoDB risolve prima di eseguire l'operazione. *Questo frammento non contiene una mappa di nomi di espressioni, perché price è un nome di attributo consentito.*

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

Se il nome di un attributo nella tabella DynamoDB è una parola riservata, inizia con un numero o contiene uno spazio, è necessaria una mappa dei nomi delle espressioni per. `Expression`

Ad esempio, se il nome dell'attributo era `1price` al posto dell'`price`esempio di codice precedente, l'esempio dovrebbe essere modificato come mostrato nell'esempio seguente.

```
        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 segnaposto per il nome di un'espressione inizia con il simbolo del cancelletto ()`#`. Una voce per la mappa dei nomi delle espressioni utilizza il segnaposto come chiave e il nome dell'attributo come valore. La mappa viene aggiunta al generatore di espressioni con il metodo. `expressionNames()` DynamoDB risolve il nome dell'attributo prima di eseguire l'operazione.

I valori di espressione non sono necessari se una funzione viene utilizzata nell'espressione stringa. Un esempio di funzione di espressione è`attribute_exists(<attribute_name>)`.

L'esempio seguente crea un file `Expression` che utilizza una funzione [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions). La stringa di espressione in questo esempio non utilizza segnaposto. Questa espressione può essere utilizzata in un'`putItem`operazione per verificare se nel database esiste già un elemento con un valore dell'`movie`attributo uguale all'attributo dell'`movie`oggetto dati.

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

La DynamoDB Developer Guide contiene informazioni complete sulle espressioni di [basso livello utilizzate](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html) con DynamoDB.

## Espressioni condizionali e condizionali
<a name="ddb-en-client-expressions-cond"></a>

Quando si utilizzano i `deleteItem()` metodi`putItem()`,`updateItem()`, e anche quando si utilizzano operazioni di transazione e batch, si utilizzano `[Expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)` oggetti per specificare le condizioni che DynamoDB deve soddisfare per procedere con l'operazione. Queste espressioni sono denominate espressioni condizionali. Per un esempio, vedi l'espressione di condizione utilizzata nel `addDeleteItem()` metodo (dopo la riga di commento 1) dell'[esempio di transazione](ddb-en-client-use-multiop-trans.md#ddb-en-client-use-multiop-trans-writeitems-opcondition) mostrato in questa guida.

Quando si utilizzano i `query()` metodi, una condizione viene espressa come a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html). La `QueryConditional` classe dispone di diversi metodi statici di convenienza che aiutano a scrivere i criteri che determinano quali elementi leggere da DynamoDB.

Per alcuni esempi di`QueryConditionals`, consultate il primo esempio di codice della [`Query`esempi di metodi](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-query-example) sezione di questa guida.

## Espressioni filtro
<a name="ddb-en-client-expressions-filter"></a>

Le espressioni di filtro vengono utilizzate nelle operazioni di scansione e interrogazione per filtrare gli elementi restituiti. 

Un'espressione di filtro viene applicata dopo che tutti i dati sono stati letti dal database, quindi il costo di lettura è lo stesso che se non ci fosse alcun filtro. [La *Amazon DynamoDB Developer* Guide contiene ulteriori informazioni sull'uso delle espressioni di filtro per le operazioni di interrogazione [e scansione](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.FilterExpression).](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html#Scan.FilterExpression)

L'esempio seguente mostra un'espressione di filtro aggiunta a una richiesta di scansione. I criteri limitano gli articoli restituiti agli articoli con un prezzo compreso tra 8,00 e 80,00€ inclusi.

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

## Espressioni di aggiornamento
<a name="ddb-en-client-expressions-update"></a>

Il metodo di DynamoDB Enhanced Client `updateItem()` fornisce un modo standard per aggiornare gli elementi in DynamoDB. [Tuttavia, quando hai bisogno di maggiori funzionalità, [UpdateExpressions](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html)fornisci una rappresentazione sicura dei tipi della sintassi delle espressioni di aggiornamento di DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html) Ad esempio, è possibile utilizzare `UpdateExpressions` per aumentare i valori senza prima leggere elementi da DynamoDB o aggiungere singoli membri a un elenco. Le espressioni di aggiornamento sono attualmente disponibili nelle estensioni personalizzate per il `updateItem()` metodo.

Per un esempio che utilizza le espressioni di aggiornamento, consultate l'[esempio di estensione personalizzata](ddb-en-client-extensions-custom.md) in questa guida.

Ulteriori informazioni sulle espressioni di aggiornamento sono disponibili nella [Amazon DynamoDB Developer Guide](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html).

# Lavora con risultati impaginati: scansioni e interrogazioni
<a name="ddb-en-client-use-multirecord"></a>

*I `scan` `batch` metodi `query` e dell'API DynamoDB Enhanced Client restituiscono risposte con una o più pagine.* Una pagina contiene uno o più elementi. Il codice può elaborare la risposta per pagina o elaborare singoli elementi.

Una risposta impaginata restituita dal client sincrono restituisce un [PageIterable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PageIterable.html)oggetto, mentre una risposta restituita dal `DynamoDbEnhancedClient` client asincrono restituisce un oggetto. `DynamoDbEnhancedAsyncClient` [PagePublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PagePublisher.html)

Questa sezione esamina l'elaborazione dei risultati impaginati e fornisce esempi che utilizzano la scansione e l'interrogazione. APIs

## Esegui la scansione di una tabella
<a name="ddb-en-client-use-multirecord-scan"></a>

Il [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))metodo dell'SDK corrisponde all'operazione [DynamoDB con lo stesso nome](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html). L'API DynamoDB Enhanced Client offre le stesse opzioni, ma utilizza un modello a oggetti familiare e gestisce l'impaginazione al posto tuo.

Innanzitutto, esploriamo l'`PageIterable`interfaccia esaminando il `scan` metodo della classe di mappatura sincrona,. [DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)

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

L'esempio seguente mostra il `scan` metodo che utilizza un'[espressione](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html) per filtrare gli elementi restituiti. [ProductCatalog](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)È l'oggetto modello che è stato mostrato in precedenza.

L'espressione di filtro mostrata dopo la riga di commento 2 limita gli `ProductCatalog` articoli che vengono restituiti a quelli con un valore di prezzo compreso tra 8,00 e 80,00 inclusi.

Questo esempio esclude anche `isbn` i valori utilizzando il `attributesToProject` metodo mostrato dopo la riga di commento 1.

Dopo la riga di commento 3, l'`PageIterable`oggetto,`pagedResults`, viene restituito dal `scan` metodo. Il `stream` metodo di `PageIterable` restituisce 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)oggetto, che è possibile utilizzare per elaborare le pagine. In questo esempio, il numero di pagine viene contato e registrato.

A partire dalla riga di commento 4, l'esempio mostra due varianti di accesso agli `ProductCatalog` elementi. La versione successiva alla riga di commento 4a scorre attraverso ogni pagina e ordina e registra gli elementi su ogni pagina. La versione successiva alla riga di commento 4b salta l'iterazione della pagina e accede direttamente agli elementi.

L'`PageIterable`interfaccia offre diversi modi per elaborare i risultati grazie alle sue due interfacce principali: e. [https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html) `Iterable`porta i `spliterator` metodi`forEach`, `iterator` e `SdkIterable` porta il `stream` metodo.

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

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

Il `scan` metodo asincrono restituisce i risultati come oggetto. `PagePublisher` L'`PagePublisher`interfaccia dispone di due `subscribe` metodi che è possibile utilizzare per elaborare le pagine di risposta. Un `subscribe` metodo proviene dall'interfaccia `org.reactivestreams.Publisher` principale. Per elaborare le pagine utilizzando questa prima opzione, passate un'`[Subscriber](https://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html)`istanza al `subscribe` metodo. Il primo esempio che segue mostra l'uso del `subscribe` metodo.

Il secondo `subscribe` metodo proviene dall'[SdkPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)interfaccia. Questa versione di `subscribe` accetta a [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)anziché a`Subscriber`. Questa variazione di `subscribe` metodo è illustrata nel secondo esempio che segue.

L'esempio seguente mostra la versione asincrona del `scan` metodo che utilizza la stessa espressione di filtro mostrata nell'esempio precedente. 

Dopo la riga di commento 3, `DynamoDbAsyncTable.scan` restituisce un oggetto. `PagePublisher` Nella riga successiva, il codice crea un'istanza dell'`org.reactivestreams.Subscriber`interfaccia`ProductCatalogSubscriber`, che sottoscrive la riga 4 `PagePublisher` dopo il commento.

L'`Subscriber`oggetto raccoglie gli `ProductCatalog` elementi da ogni pagina del `onNext` metodo dopo la riga di commento 8 nell'esempio di `ProductCatalogSubscriber` classe. Gli elementi sono memorizzati nella `List` variabile privata e vi si accede nel codice di chiamata con il `ProductCatalogSubscriber.getSubscribedItems()` metodo. Viene chiamato dopo la riga di commento 5.

Dopo aver recuperato l'elenco, il codice ordina tutti gli `ProductCatalog` articoli in base al prezzo e registra ogni articolo.

La `ProductCatalogSubscriber` classe [CountDownLatch](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)in the blocca il thread chiamante fino a quando tutti gli elementi non sono stati aggiunti all'elenco prima di continuare dopo la riga di commento 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;
        }
    }
```

Il seguente esempio di frammento utilizza la versione del `PagePublisher.subscribe` metodo che accetta una riga `Consumer` successiva al commento 6. Il parametro Java lambda utilizza le pagine, che elaborano ulteriormente ogni elemento. In questo esempio, ogni pagina viene elaborata e gli elementi di ogni pagina vengono ordinati e quindi registrati.

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

Il `items` metodo di `PagePublisher` decodifica le istanze del modello in modo che il codice possa elaborare direttamente gli elementi. Questo approccio è illustrato nel frammento seguente.

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

## Eseguire una query su una tabella
<a name="ddb-en-client-use-multirecord-query"></a>

È possibile utilizzare il DynamoDB Enhanced Client per interrogare la tabella e recuperare più elementi che soddisfano criteri specifici. Il [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))metodo trova gli elementi in base ai valori della chiave primaria utilizzando le `@DynamoDbSortKey` annotazioni `@DynamoDbPartitionKey` opzionali definite nella classe di dati.

Il `query()` metodo richiede un valore di chiave di partizione e accetta facoltativamente le condizioni della chiave di ordinamento per perfezionare ulteriormente i risultati. Come l'`scan`API, le query restituiscono un `PageIterable` per le chiamate sincrone e un per le chiamate asincrone. `PagePublisher`

### `Query`esempi di metodi
<a name="ddb-en-client-use-multirecord-query-example"></a>

L'esempio di codice del `query()` metodo che segue utilizza la `MovieActor` classe. La classe di dati definisce una chiave primaria composita composta dall'**`movie`**attributo come chiave di partizione e dall'**`actor`**attributo come chiave di ordinamento. 

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

Gli esempi di codice che seguono eseguono una query sui seguenti elementi.

#### Elementi nella `MovieActor` tabella
<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'}
```

Il codice seguente definisce due `QueryConditional` istanze: `keyEqual` (dopo la riga di commento 1) e `sortGreaterThanOrEqualTo` (dopo la riga di commento 1a).

#### Interroga gli elementi per chiave di partizione
<a name="keyEqual-query-conditional-example"></a>

L'`keyEqual`istanza abbina gli elementi con un valore della chiave di partizione pari a. **`movie01`** 

Questo esempio definisce anche un'espressione di filtro dopo la riga di commento 2 che filtra qualsiasi elemento che non ha un **`actingschoolname`**valore.

`QueryEnhancedRequest`Combina la condizione chiave e l'espressione di filtro per la query.

```
    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 — Emissione utilizzando l'`keyEqual`interrogazione condizionale**  
Di seguito è riportato l'output dell'esecuzione del metodo. L'output mostra gli elementi con un `movieName` valore di **movie01** e non visualizza alcun elemento `actingSchoolName` uguale a. **`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'}
```

#### Interroga gli elementi per chiave di partizione e chiave di ordinamento
<a name="sort-type-query-conditional-example"></a>

`sortGreaterThanOrEqualTo``QueryConditional`**Perfeziona la corrispondenza della chiave di partizione (**movie01**) aggiungendo una condizione di chiave di ordinamento per valori maggiori o uguali a actor2.**

[`QueryConditional`i metodi](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) che iniziano con `sort` richiedono che il valore della chiave di partizione corrisponda e perfezionano ulteriormente la query mediante un confronto basato sul valore della chiave di ordinamento. `Sort`nel nome del metodo non significa che i risultati siano ordinati, ma che per il confronto verrà utilizzato un valore di chiave di ordinamento.

Nel frammento seguente, modifichiamo la richiesta di query mostrata in precedenza dopo la riga di commento 3. Questo frammento sostituisce la query condizionale «KeyEqual» con la query condizionale "sortGreaterThanOrEqualTo" definita dopo la riga di commento 1a. Il codice seguente rimuove anche l'espressione del filtro.

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

**Example — Emissione utilizzando la `sortGreaterThanOrEqualTo` query condizionale**  
L'output seguente mostra i risultati dell'interrogazione. **La query restituisce gli elementi con un `movieName` valore uguale a **movie01** e solo gli elementi che hanno un `actorName` valore maggiore o uguale a actor2.** Poiché rimuoviamo il filtro, la query restituisce gli elementi che non hanno alcun valore per l'attributo. `actingSchoolName`  

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

# Esegui operazioni in batch
<a name="ddb-en-client-use-multiop-batch"></a>

[L'API DynamoDB Enhanced Client offre due metodi batch [`batchGetItem`, () e (](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))

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

Con [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))questo metodo, è possibile recuperare fino a 100 singoli elementi su più tabelle in un'unica richiesta complessiva. L'esempio seguente utilizza le classi di [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)dati [`Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust)e mostrate in precedenza.

Nell'esempio dopo le righe 1 e 2, create `[ReadBatch](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ReadBatch.html)` oggetti che successivamente aggiungete come parametri al `batchGetItem()` metodo dopo la riga di commento 3. 

Il codice dopo la riga di commento 1 crea il batch da leggere dalla `Customer` tabella. Il codice dopo la riga di commento 1a mostra l'uso di un `[GetItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/GetItemEnhancedRequest.Builder.html)` builder che accetta un valore di chiave primaria e un valore di chiave di ordinamento per specificare l'elemento da leggere. Se la classe di dati ha una chiave composita, è necessario fornire sia il valore della chiave di partizione che il valore della chiave di ordinamento. 

A differenza di specificare i valori chiave per richiedere un elemento, è possibile utilizzare una classe di dati per richiedere un elemento, come mostrato dopo la riga di commento 1b. L'SDK estrae i valori chiave dietro le quinte prima di inviare la richiesta.

[Quando si specifica l'elemento utilizzando l'approccio basato su chiavi, come mostrato nelle due istruzioni successive a 2a, è anche possibile specificare che DynamoDB deve eseguire una lettura fortemente coerente.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html) Quando viene utilizzato, il `consistentRead()` metodo deve essere utilizzato su tutti gli elementi richiesti per la stessa tabella.

Per recuperare gli elementi trovati da DynamoDB, utilizzate `[resultsForTable() ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#resultsForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` il metodo mostrato dopo la riga di commento 4. Chiamate il metodo per ogni tabella che è stata letta nella richiesta. `resultsForTable()`restituisce un elenco di elementi trovati che è possibile elaborare utilizzando qualsiasi `java.util.List` metodo. Questo esempio registra ogni elemento.

Per scoprire elementi che DynamoDB non ha elaborato, utilizzate l'approccio dopo la riga di commento 5. La `BatchGetResultPage` classe utilizza il `[unprocessedKeysForTable()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#unprocessedKeysForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` metodo che consente di accedere a ogni chiave non elaborata. Il [riferimento all'BatchGetItem API](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html) contiene ulteriori informazioni sulle situazioni che generano elementi non elaborati.

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

Si supponga che i seguenti elementi siano presenti nelle due tabelle prima di eseguire il codice di esempio.

### Elementi nelle tabelle
<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'}
```

L'output seguente mostra gli elementi restituiti e registrati dopo la riga di commento 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'}
```

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

Il `batchWriteItem()` metodo inserisce o elimina più elementi in una o più tabelle. È possibile specificare fino a 25 singole operazioni di inserimento o eliminazione nella richiesta. L'esempio seguente utilizza le classi [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)e [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)model mostrate in precedenza.

`WriteBatch`gli oggetti vengono creati dopo le righe di commento 1 e 2. Per la `ProductCatalog` tabella, il codice inserisce un elemento ed elimina un elemento. Per la `MovieActor` tabella dopo la riga di commento 2, il codice inserisce due elementi e ne elimina uno.

Il `batchWriteItem` metodo viene chiamato dopo la riga di commento 3. Il `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteItemEnhancedRequest.Builder.html)` parametro fornisce le richieste batch per ogni tabella.

L'`[BatchWriteResult](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteResult.html)`oggetto restituito fornisce metodi separati per ogni operazione per visualizzare le richieste non elaborate. Il codice dopo la riga di commento 4a fornisce le chiavi per le richieste di cancellazione non elaborate e il codice dopo la riga di commento 4b fornisce gli elementi put non elaborati.

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

I seguenti metodi di supporto forniscono gli oggetti del modello per le operazioni di inserimento ed eliminazione.

### Metodi di supporto
<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.     }
```

Si supponga che le tabelle contengano i seguenti elementi prima di eseguire il codice di esempio.

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

Al termine del codice di esempio, le tabelle contengono gli elementi seguenti.

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

Si noti nella `MovieActor` tabella che l'elemento del `Blue Jasmine` filmato è stato sostituito con l'elemento utilizzato nella richiesta put acquisita tramite il metodo `getMovieActorBlanchettPartial()` helper. Se non è stato fornito un valore dell'attributo data bean, il valore nel database viene rimosso. Questo è il motivo per cui il risultato `actingSchoolName` è nullo per l'elemento del `Blue Jasmine` filmato.

**Nota**  
[Sebbene la documentazione dell'API suggerisca che è possibile utilizzare espressioni condizionali e che la capacità consumata e le metriche di raccolta possano essere restituite con richieste di immissione ed [eliminazione](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.html) individuali, questo non è il caso in uno scenario di scrittura in batch.](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PutItemEnhancedRequest.html) Per migliorare le prestazioni delle operazioni in batch, queste singole opzioni vengono ignorate.

# Esegui operazioni di transazione
<a name="ddb-en-client-use-multiop-trans"></a>

L'API DynamoDB Enhanced Client fornisce `transactGetItems()` i metodi e. `transactWriteItems()` I metodi di transazione dell'SDK for Java forniscono atomicità, coerenza, isolamento e durabilità (ACID) nelle tabelle DynamoDB, aiutandoti a mantenere la correttezza dei dati nelle tue applicazioni.

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

Il `[transactGetItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactGetItems(java.util.function.Consumer))` metodo accetta fino a 100 richieste individuali di articoli. Tutti gli elementi vengono letti in un'unica transazione atomica. L'*Amazon DynamoDB Developer* Guide contiene informazioni sulle [condizioni che causano il fallimento di `transactGetItems()` un metodo](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txgetitems) e anche sul livello di isolamento utilizzato durante le chiamate. `[transactGetItem()](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-isolation)`

Dopo la riga di commento 1 nell'esempio seguente, il codice chiama il `transactGetItems()` metodo con un `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html)` parametro. Il builder `[addGetItem()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html#addGetItem(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource,T))` viene richiamato tre volte con un oggetto dati che contiene i valori chiave che l'SDK utilizzerà per generare la richiesta finale.

La richiesta restituisce un elenco di `[Document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html)` oggetti dopo la riga di commento 2. L'elenco di documenti restituito contiene istanze di [Document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html) non nulle dei dati degli articoli nello stesso ordine richiesto. Il `[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))` metodo converte un oggetto non tipizzato in un `Document` oggetto Java digitato se sono stati restituiti i dati dell'elemento, altrimenti restituisce 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());
        }
    }
```

Le tabelle DynamoDB contengono i seguenti elementi prima dell'esecuzione dell'esempio di codice.

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

Viene registrato il seguente output. Se un elemento viene richiesto ma non viene trovato, non viene restituito, come nel caso della richiesta per il film denominato`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'}
```

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

`[transactWriteItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))`Accetta fino a 100 azioni di inserimento, aggiornamento o eliminazione in una singola transazione atomica su più tabelle. La *Amazon DynamoDB Developer* Guide contiene dettagli sulle restrizioni e le condizioni di errore del funzionamento del servizio [DynamoDB sottostante](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems).

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

Nell'esempio seguente, sono richieste quattro operazioni per due tabelle. Le classi del modello corrispondenti [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)e [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class)sono state mostrate in precedenza.

Ciascuna delle tre operazioni possibili (put, update ed delete) utilizza un parametro di richiesta dedicato per specificare i dettagli. 

Il codice dopo la riga di commento 1 mostra la semplice variazione del metodo. `addPutItem()` Il metodo accetta un `[MappedTableResource](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/MappedTableResource.html)` oggetto e l'istanza dell'oggetto dati da inserire. L'istruzione dopo la riga di commento 2 mostra la variante che accetta un'`[TransactPutItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactPutItemEnhancedRequest.html)`istanza. Questa variante consente di aggiungere altre opzioni nella richiesta, ad esempio un'espressione di condizione. Un [esempio](#ddb-en-client-use-multiop-trans-writeitems-opcondition) successivo mostra un'espressione di condizione per una singola operazione.

Viene richiesta un'operazione di aggiornamento dopo la riga di commento 3. `[TransactUpdateItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactUpdateItemEnhancedRequest.Builder.html)`ha un `ignoreNulls()` metodo che consente di configurare ciò che l'SDK fa con `null` i valori sull'oggetto del modello. Se il `ignoreNulls()` metodo restituisce true, l'SDK non rimuove i valori degli attributi della tabella per gli attributi degli oggetti dati che sono. `null` Se il `ignoreNulls()` metodo restituisce false, l'SDK richiede al servizio DynamoDB di rimuovere gli attributi dall'elemento nella tabella. Il valore predefinito per `ignoreNulls` è false.

L'istruzione dopo la riga di commento 4 mostra la variazione di una richiesta di eliminazione che richiede un oggetto dati. Il client avanzato estrae i valori chiave prima di inviare la richiesta 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())
        );
    }
```

I seguenti metodi di supporto forniscono gli oggetti dati per i parametri. `add*Item`

#### Metodi di supporto
<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;
    }
```

Le tabelle DynamoDB contengono i seguenti elementi prima dell'esecuzione dell'esempio di codice.

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

I seguenti elementi sono presenti nelle tabelle al termine dell'esecuzione del codice.

```
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'elemento sulla riga 2 è stato eliminato e le righe 3 e 5 mostrano gli elementi che sono stati inseriti. La riga 4 mostra l'aggiornamento della riga 1. Il `price` valore è l'unico valore che è cambiato sull'elemento. Se `ignoreNulls()` avesse restituito false, la riga 4 sarebbe simile alla riga seguente.

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

### Esempio di controllo delle condizioni
<a name="ddb-en-client-use-multiop-trans-writeitems-checkcond"></a>

L'esempio seguente mostra l'uso di un controllo delle condizioni. Un controllo delle condizioni viene utilizzato per verificare l'esistenza di un elemento o per verificare la condizione di attributi specifici di un elemento nel database. L'articolo registrato nel controllo delle condizioni non può essere utilizzato in un'altra operazione della transazione.

**Nota**  
Non è possibile fare riferimento allo stesso item con diverse operazioni all'interno della stessa transazione. Ad esempio, non è possibile eseguire un controllo delle condizioni e anche tentare di aggiornare lo stesso articolo nella stessa transazione.

L'esempio mostra una per ogni tipo di operazione in una richiesta transazionale di scrittura di elementi. Dopo la riga di commento 2, il `addConditionCheck()` metodo fornisce la condizione che fallisce la transazione se il `conditionExpression` parametro restituisce un risultato positivo. `false` L'espressione di condizione restituita dal metodo mostrato nel blocco Helper methods verifica se l'anno di premiazione del film non `Sophie's Choice` è uguale a. `1982` In caso affermativo, l'espressione restituisce `false` e la transazione ha esito negativo.

Questa guida illustra in modo approfondito [le espressioni](ddb-en-client-expressions.md) in un altro argomento.

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

I seguenti metodi di supporto vengono utilizzati nell'esempio di codice precedente.

#### Metodi di supporto
<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;
    }
```

Le tabelle DynamoDB contengono i seguenti elementi prima dell'esecuzione dell'esempio di codice.

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

I seguenti elementi sono presenti nelle tabelle al termine dell'esecuzione del codice.

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

Gli elementi rimangono invariati nelle tabelle perché la transazione non è riuscita. Il `actingYear` valore del filmato `Sophie's Choice` è`1982`, come mostrato nella riga 2 degli elementi della tabella prima della chiamata del `transactWriteItem()` metodo.

Per acquisire le informazioni di annullamento della transazione, racchiudi la chiamata al `transactWriteItems()` metodo in un `try` blocco e `catch` il [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). Dopo la riga di commento 4 dell'esempio, il codice registra ogni `[CancellationReason](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CancellationReason.html)` oggetto. Poiché il codice che segue la riga di commento 3 dell'esempio specifica che devono essere restituiti i valori per l'elemento che ha causato il fallimento della transazione, nel registro vengono visualizzati i valori non elaborati del database per l'elemento del `Sophie's Choice` filmato.

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

### Esempio di condizione di operazione singola
<a name="ddb-en-client-use-multiop-trans-writeitems-opcondition"></a>

L'esempio seguente mostra l'uso di una condizione su una singola operazione in una richiesta di transazione. L'operazione di eliminazione dopo la riga di commento 1 contiene una condizione che verifica il valore dell'elemento di destinazione dell'operazione rispetto al database. In questo esempio, l'espressione condizionale creata con il metodo helper dopo la riga di commento 2 specifica che l'elemento deve essere eliminato dal database se l'anno di recitazione del film non è uguale al 2013.

[Le espressioni](ddb-en-client-expressions.md) vengono discusse più avanti in questa guida.

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

I seguenti metodi di supporto vengono utilizzati nell'esempio di codice precedente.

#### Metodi di supporto
<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;
    }
```

Le tabelle DynamoDB contengono i seguenti elementi prima dell'esecuzione dell'esempio di codice.

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

I seguenti elementi sono presenti nelle tabelle al termine dell'esecuzione del codice.

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

Gli elementi rimangono invariati nelle tabelle perché la transazione non è riuscita. Il `actingYear` valore del filmato `Blue Jasmine` è quello `2013` mostrato alla riga 2 dell'elenco degli elementi prima dell'esecuzione dell'esempio di codice.

Le seguenti righe vengono registrate nella 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)
```

# Usa indici secondari
<a name="ddb-en-client-use-secindex"></a>

Gli indici secondari migliorano l'accesso ai dati definendo chiavi alternative da utilizzare nelle operazioni di interrogazione e scansione. Gli indici secondari globali (GSI) hanno una chiave di partizione e una chiave di ordinamento che possono essere diverse da quelle della tabella di base. Al contrario, gli indici secondari locali (LSI) utilizzano la chiave di partizione dell'indice primario.

## Annota la classe di dati con annotazioni dell'indice secondario
<a name="ddb-en-client-use-secindex-annomodel"></a>

Gli attributi che partecipano agli indici secondari richiedono l'annotazione `@DynamoDbSecondaryPartitionKey` o`@DynamoDbSecondarySortKey`.

La classe seguente mostra le annotazioni per due indici. Il nome GSI *SubjectLastPostedDateIndex*utilizza l'`Subject`attributo per la chiave di partizione e il `LastPostedDateTime` per la chiave di ordinamento. L'LSI denominato *ForumLastPostedDateIndex*utilizza la `ForumName` come chiave di partizione e `LastPostedDateTime` come chiave di ordinamento.

Si noti che l'`Subject`attributo ha un duplice ruolo. È la chiave di ordinamento della chiave primaria e la chiave di partizione del GSI denominato. *SubjectLastPostedDateIndex*

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

La `MessageThread` classe è adatta all'uso come classe di dati per la [tabella Thread di esempio](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AppendixSampleTables.html) nella *Amazon DynamoDB Developer Guide*.

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

## Crea l'indice
<a name="ddb-en-client-use-secindex-confindex"></a>

A partire dalla versione 2.20.86 dell'SDK for Java, il `createTable()` metodo genera automaticamente indici secondari dalle annotazioni delle classi di dati. Per impostazione predefinita, tutti gli attributi della tabella di base vengono copiati in un indice e i valori di throughput assegnati sono 20 unità di capacità di lettura e 20 unità di capacità di scrittura.

Tuttavia, se si utilizza una versione SDK precedente alla 2.20.86, è necessario creare l'indice insieme alla tabella, come mostrato nell'esempio seguente. Questo esempio crea i due indici per la tabella. `Thread` Il parametro [builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html) dispone di metodi per configurare entrambi i tipi di indici, come illustrato dopo le righe di commento 1 e 2. Utilizzate il `indexName()` metodo del generatore di indici per associare i nomi degli indici specificati nelle annotazioni delle classi di dati al tipo di indice desiderato.

Questo codice configura tutti gli attributi della tabella in modo che finiscano in entrambi gli indici dopo le righe di commento 3 e 4. Ulteriori informazioni sulle [proiezioni degli attributi](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html#LSI.Projections) sono disponibili nella *Amazon DynamoDB Developer* Guide.

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

## Esegui una query utilizzando un indice
<a name="ddb-en-client-use-secindex-query"></a>

L’esempio seguente esegue una query sull’indice globale secondario *ForumLastPostedDateIndex*.

Dopo la riga di commento 2, create un [QueryConditional](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html)oggetto che è necessario quando si chiama il [DynamoDbIndexmetodo.query ()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbIndex.html#query(java.util.function.Consumer)). 

Si ottiene un riferimento all'indice che si desidera interrogare dopo la riga di commento 3 inserendo il nome dell'indice. Dopo la riga di commento 4, si chiama il `query()` metodo sull'indice che passa l'`QueryConditional`oggetto. 

È inoltre possibile configurare la query per restituire tre valori di attributo, come mostrato dopo la riga di commento 5. Se non `attributesToProject()` viene chiamata, la query restituisce tutti i valori degli attributi. Notate che i nomi degli attributi specificati iniziano con lettere minuscole. Questi nomi di attributi corrispondono a quelli utilizzati nella tabella, non necessariamente ai nomi degli attributi della classe di dati.

Dopo la riga di commento 6, scorri i risultati e registra ogni elemento restituito dalla query, inoltre memorizzalo nell'elenco per restituirlo al chiamante.

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

I seguenti elementi sono presenti nel database prima dell'esecuzione della query.

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

Le istruzioni di registrazione alle righe 1 e 6 generano il seguente output della console.

```
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 query ha restituito elementi con un `forumName` valore di *Forum02* e un `lastPostedDateTime` valore maggiore o uguale a 2023.03.31.* I risultati mostrano `message` valori con una stringa vuota sebbene `message` gli attributi abbiano valori nell'indice. Questo perché l'attributo message non è stato proiettato dal codice dopo la riga di commento 5. 

# Usa funzionalità di mappatura avanzate
<a name="ddb-en-client-adv-features"></a>

Scopri le funzionalità avanzate dello schema delle tabelle nell'API DynamoDB Enhanced Client.

## Comprendi i tipi di schemi delle tabelle
<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)`è l'interfaccia per la funzionalità di mappatura dell'API DynamoDB Enhanced Client. Può mappare un oggetto di dati da e verso una mappa di. [AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html) Un `TableSchema` oggetto deve conoscere la struttura della tabella che sta mappando. Queste informazioni sulla struttura vengono memorizzate in 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)oggetto.

L'API client avanzata ha diverse implementazioni di`TableSchema`, che seguono. 

### Schema di tabella generato da classi annotate
<a name="ddb-en-client-adv-features-schema-mapped"></a>

È un'operazione moderatamente costosa creare una a `TableSchema` partire da classi annotate, quindi consigliamo di farlo una sola volta, all'avvio dell'applicazione.

 [ BeanTableSchema ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/BeanTableSchema.html)   
Questa implementazione è costruita sulla base degli attributi e delle annotazioni di una classe bean. Un esempio di questo approccio è illustrato nella [sezione Guida introduttiva](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean).  
Se a non `BeanTableSchema` si comporta come previsto, abilita la registrazione di debug per. `software.amazon.awssdk.enhanced.dynamodb.beans`

[ImmutableTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/ImmutableTableSchema.html)  
Questa implementazione è costruita da una classe di dati immutabile. Questo approccio è descritto nella sezione. [Lavora con classi di dati immutabili](ddb-en-client-use-immut.md)

### Schema di tabella generato con un builder
<a name="ddb-en-client-adv-features-schema-static"></a>

`TableSchema`I seguenti sono creati a partire dal codice utilizzando un builder. Questo approccio è meno costoso dell'approccio che utilizza classi di dati annotate. L'approccio builder evita l'uso di annotazioni e non richiede standard di denominazione. JavaBean 

[StaticTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticTableSchema.html)  
Questa implementazione è progettata per classi di dati mutabili. La sezione introduttiva di questa guida ha dimostrato come [generare un file `StaticTableSchema` utilizzando un builder](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)  
Analogamente a come si crea un`StaticTableSchema`, si genera un'implementazione di questo tipo `TableSchema` utilizzando un [builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticImmutableTableSchema.html) da utilizzare con classi di dati immutabili.

### Schema di tabella per dati senza schema fisso
<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)  
A differenza di altre implementazioni di`TableSchema`, non si definiscono gli attributi per un'`DocumentTableSchema`istanza. Di solito, si specificano solo chiavi primarie e fornitori di convertitori di attributi. Un'`EnhancedDocument`istanza fornisce gli attributi creati da singoli elementi o da una stringa JSON.

# Includi o escludi gli attributi in modo esplicito
<a name="ddb-en-client-adv-features-inex-attr"></a>

L'API DynamoDB Enhanced Client offre annotazioni per escludere gli attributi delle classi di dati dal diventare attributi su una tabella. Con l'API, puoi anche utilizzare un nome di attributo diverso dal nome dell'attributo della classe di dati.

## Escludi gli attributi
<a name="ddb-en-client-adv-features-inex-attr-ex"></a>

Per ignorare gli attributi che non devono essere mappati su una tabella DynamoDB, contrassegna l'attributo con l'annotazione. `@DynamoDbIgnore`

```
private String internalKey;

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

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

Per modificare il nome di un attributo utilizzato nella tabella DynamoDB, contrassegnalo con `@DynamoDbAttribute` l'annotazione e fornisci un nome diverso.

```
private String internalKey;

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

# Controlla la conversione degli attributi
<a name="ddb-en-client-adv-features-conversion"></a>

Per impostazione predefinita, uno schema tabellare fornisce convertitori per molti tipi Java comuni tramite un'implementazione predefinita dell'`[AttributeConverterProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverterProvider.html)`interfaccia. È possibile modificare il comportamento predefinito generale con un’implementazione `AttributeConverterProvider` personalizzata. Inoltre, è possibile modificare il convertitore per un singolo attributo.

Per un elenco dei convertitori disponibili, consultate l'[AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html)interfaccia Java doc.

## Fornisci fornitori di convertitori di attributi personalizzati
<a name="ddb-en-client-adv-features-conversion-prov"></a>

È possibile fornire una singola `AttributeConverterProvider` o una catena di messaggi ordinati `AttributeConverterProvider` tramite l'`@DynamoDbBean``(converterProviders = {…})`annotazione. Qualsiasi personalizzazione `AttributeConverterProvider` deve estendere l'`AttributeConverterProvider`interfaccia.

Tieni presente che se fornisci la tua catena di fornitori di convertitori di attributi, sostituirai il provider di convertitori predefinito,`DefaultAttributeConverterProvider`. Se si desidera utilizzare la funzionalità di`DefaultAttributeConverterProvider`, è necessario includerla nella catena. 

È anche possibile annotare il bean con un array `{}` vuoto. Ciò disabilita l'uso di qualsiasi fornitore di convertitori di attributi, incluso quello predefinito. In questo caso tutti gli attributi che devono essere mappati devono avere un proprio convertitore di attributi.

Il frammento seguente mostra un singolo fornitore di convertitori.

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

}
```

Il seguente frammento mostra l'uso di una catena di fornitori di convertitori. Poiché l'SDK predefinito viene fornito per ultimo, ha la priorità più bassa.

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

}
```

I generatori di schemi di tabelle statiche hanno un `attributeConverterProviders()` metodo che funziona allo stesso modo. Questo è mostrato nel frammento seguente.

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

## Sovrascrivi la mappatura di un singolo attributo
<a name="ddb-en-client-adv-features-conversion-single"></a>

Per sovrascrivere il modo in cui viene mappato un singolo attributo, fornisci un `AttributeConverter` per l'attributo. Questa aggiunta sostituisce tutti i convertitori forniti `AttributeConverterProviders` nello schema della tabella. Questo aggiunge un convertitore personalizzato solo per quell'attributo. Altri attributi, anche quelli dello stesso tipo, non utilizzeranno quel convertitore a meno che non sia specificato esplicitamente per quegli altri attributi.

L'`@DynamoDbConvertedBy`annotazione viene utilizzata per specificare la `AttributeConverter` classe personalizzata, come mostrato nel frammento seguente.

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

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

I costruttori di schemi statici hanno un metodo di creazione di attributi equivalente. `attributeConverter()` Questo metodo accetta un'istanza di an `AttributeConverter` come illustrato di seguito.

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

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

Questo esempio mostra un'`AttributeConverterProvider`implementazione che fornisce un convertitore di attributi per [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)gli oggetti. 

La `SimpleUser` classe seguente contiene un attributo denominato `lastUsedCookie` che è un'istanza di`HttpCookie`.

Il parametro delle `@DynamoDbBean` annotazioni elenca le due `AttributeConverterProvider` classi che forniscono convertitori.

------
#### [ 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`Nell'esempio seguente viene fornita un'istanza di un. `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);
        }
    }
```

### Codice di conversione
<a name="ddb-en-client-adv-features-conversion-example-code"></a>

Nel `transformFrom()` metodo della `HttpCookieConverter` classe seguente, il codice riceve un'`HttpCookie`istanza e la trasforma in una mappa DynamoDB memorizzata come attributo.

Il `transformTo()` metodo riceve un parametro di mappa DynamoDB, quindi richiama `HttpCookie` il costruttore che richiede un nome e un valore.

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

# Modifica il comportamento di aggiornamento degli attributi
<a name="ddb-en-client-adv-features-upd-behavior"></a>

*È possibile personalizzare il comportamento di aggiornamento dei singoli attributi quando si esegue un'operazione di aggiornamento.* [Alcuni esempi di operazioni di aggiornamento nell'API DynamoDB Enhanced Client [sono updateItem](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#updateItem(T)) () e (). transactWriteItems](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))

Ad esempio, immaginate di voler memorizzare un timestamp *creato su* un vostro record. Tuttavia, desideri che il suo valore venga scritto solo se non esiste alcun valore esistente per l'attributo già nel database. In questo caso, si utilizza il comportamento di `[WRITE\$1IF\$1NOT\$1EXISTS](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html#WRITE_IF_NOT_EXISTS)` aggiornamento.

L'esempio seguente mostra l'annotazione che aggiunge il comportamento all'`createdOn`attributo.

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

È possibile dichiarare lo stesso comportamento di aggiornamento quando si crea uno schema di tabella statico, come mostrato nell'esempio seguente dopo la riga di commento 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();
```

# Appiattisci gli attributi di altre classi
<a name="ddb-en-client-adv-features-flatmap"></a>

Se gli attributi della tabella sono distribuiti tra diverse classi Java, tramite ereditarietà o composizione, l'API Enhanced Client di DynamoDB fornisce supporto per riunire gli attributi in un'unica classe.

## Usa l'ereditarietà
<a name="ddb-en-client-adv-features-flatmap-inheritance"></a>

Se le tue classi utilizzano l'ereditarietà, usa i seguenti approcci per appiattire la gerarchia.

### Usa fagioli annotati
<a name="ddb-en-client-adv-features-flatmap-inheritance-anno"></a>

Per l'approccio all'annotazione, entrambe le classi devono contenere l'`@DynamoDbBean`annotazione e una classe deve contenere una o più annotazioni chiave primarie.

Di seguito vengono illustrati esempi di classi di dati che hanno una relazione di ereditarietà.

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

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

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

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

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

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

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

[`onMethod`L'opzione](https://projectlombok.org/features/experimental/onX) di Lombok copia le annotazioni DynamoDB basate sugli attributi, ad esempio, sul codice generato. `@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;
}
```

------

### Usa schemi statici
<a name="ddb-en-client-adv-features-flatmap-inheritance-static"></a>

Per l'approccio allo schema statico, utilizzate il `extend()` metodo del generatore per comprimere gli attributi della classe principale nella classe figlia. Questo è mostrato dopo la riga di commento 1 nell'esempio seguente.

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

Il precedente esempio di schema statico utilizza le seguenti classi di dati. Poiché la mappatura viene definita quando si crea lo schema statico della tabella, le classi di dati non richiedono annotazioni.

#### Classi di dati
<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;
}
```

------

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

Se le tue classi usano la composizione, usa i seguenti approcci per appiattire la gerarchia.

### Usa fagioli annotati
<a name="ddb-en-client-adv-features-flatmap-comp-anno"></a>

L'`@DynamoDbFlatten`annotazione appiattisce la classe contenuta.

I seguenti esempi di classi di dati utilizzano l'`@DynamoDbFlatten`annotazione per aggiungere efficacemente tutti gli attributi della `GenericRecord` classe contenuta alla classe. `Customer`

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

------

Puoi usare l'annotazione flatten per appiattire tutte le diverse classi idonee di cui hai bisogno. Vengono applicati i vincoli seguenti:
+ Tutti i nomi degli attributi devono essere unici dopo essere stati appiattiti.
+ Non deve mai esserci più di una chiave di partizione, chiave di ordinamento o nome di tabella.

### Usa schemi statici
<a name="ddb-en-client-adv-features-flatmap-comp-static"></a>

Quando crei uno schema di tabella statico, usa il `flatten()` metodo del generatore. Fornite anche i metodi getter e setter che identificano la classe contenuta.

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

Il precedente esempio di schema statico utilizza le seguenti classi di dati.

#### Classi di dati
<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;
}
```

------

Puoi utilizzare il modello builder per appiattire tutte le diverse classi idonee di cui hai bisogno.

## Implicazioni per altro codice
<a name="ddb-en-client-adv-features-flatmap-compare"></a>

Quando si utilizza l'`@DynamoDbFlatten`attributo (o il metodo `flatten()` builder), l'elemento in DynamoDB contiene un attributo per ogni attributo dell'oggetto composto. Include anche gli attributi dell'oggetto che lo compone. 

Al contrario, se annotate una classe di dati con una classe composta e non la utilizzate`@DynamoDbFlatten`, l'elemento viene salvato con l'oggetto composto come attributo singolo.

Ad esempio, confrontate la `Customer` classe mostrata nell'esempio di [appiattimento con l'esempio di composizione con](#ddb-en-client-adv-features-flatmap-comp-anno) e senza appiattimento dell'attributo. `record` È possibile visualizzare la differenza con JSON come illustrato nella tabella seguente.


****  

| Con appiattimento | Senza appiattimento | 
| --- | --- | 
| 3 attributi | 2 attributi | 
|  <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 differenza diventa importante se si dispone di altro codice che accede alla tabella DynamoDB che prevede di trovare determinati attributi.

# Lavora con attributi che sono bean, mappe, elenchi e set
<a name="ddb-en-client-adv-features-nested"></a>

Una definizione di bean, come la `Person` classe mostrata di seguito, potrebbe definire proprietà (o attributi) che si riferiscono a tipi con attributi aggiuntivi. Ad esempio, nella `Person` classe, `mainAddress` c'è una proprietà che si riferisce a un `Address` bean che definisce attributi di valore aggiuntivi. `addresses`si riferisce a una mappa Java, i cui elementi si riferiscono ai `Address` bean. Questi tipi complessi possono essere considerati contenitori di attributi semplici da utilizzare per il valore dei dati nel contesto di DynamoDB. 

*DynamoDB si riferisce alle proprietà di valore degli elementi nidificati, come mappe, elenchi o bean, come attributi nidificati.* *La [Amazon DynamoDB Developer](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) Guide si riferisce al formato salvato di una mappa, un elenco o un bean Java come tipo di documento.* Gli attributi semplici utilizzati per il loro valore di dati in Java sono denominati *tipi scalari* in DynamoDB. *I set, che contengono più elementi scalari dello stesso tipo e sono denominati tipi di set.* 

È importante sapere che l'API DynamoDB Enhanced Client converte una proprietà che è bean in un tipo di documento di mappa DynamoDB quando viene salvata.

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

## Salva tipi complessi
<a name="ddb-en-client-adv-features-nested-mapping"></a>

### Usa classi di dati annotate
<a name="ddb-en-client-adv-features-nested-map-anno"></a>

Puoi salvare gli attributi annidati per le classi personalizzate semplicemente annotandoli. La `Address` classe e la `PhoneNumber` classe mostrate in precedenza vengono annotate solo con l'annotazione. `@DynamoDbBean` Quando l'API DynamoDB Enhanced Client crea lo schema della tabella per la classe con `Person` il seguente frammento, l'API rileva l'uso delle classi `PhoneNumber` and e crea le mappature corrispondenti per `Address` funzionare con DynamoDB.

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

### Usa schemi astratti con i builder
<a name="ddb-en-client-adv-features-nested-map-builder"></a>

L'approccio alternativo consiste nell'utilizzare generatori di schemi di tabelle statiche per ogni classe bean annidata, come mostrato nel codice seguente.

Gli schemi di tabella per le `PhoneNumber` classi `Address` and sono astratti, nel senso che non possono essere utilizzati con una tabella DynamoDB. Questo perché mancano di definizioni per la chiave primaria. Vengono tuttavia utilizzati come schemi annidati nello schema tabellare della classe. `Person`

Dopo le righe di commento 1 e 2 nella definizione di`PERSON_TABLE_SCHEMA`, viene visualizzato il codice che utilizza gli schemi di tabella astratti. L'uso di `documentOf` nel `EnhanceType.documentOf(...)` metodo non indica che il metodo restituisca un `EnhancedDocument` tipo di Enhanced Document API. Il `documentOf(...)` metodo in questo contesto restituisce un oggetto che sa come mappare l'argomento della classe da e verso gli attributi della tabella DynamoDB utilizzando l'argomento dello schema della tabella.

#### Codice dello schema statico
<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();
```

## Attributi di progetto di tipi complessi
<a name="ddb-en-client-adv-features-nested-projection"></a>

Per `query()` i `scan()` metodi, è possibile specificare quali attributi si desidera vengano restituiti nei risultati utilizzando chiamate di metodo come `addNestedAttributeToProject()` e`attributesToProject()`. L'API DynamoDB Enhanced Client converte i parametri di chiamata al metodo Java [in espressioni di proiezione](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html) prima dell'invio della richiesta.

L'esempio seguente popola la `Person` tabella con due elementi, quindi esegue tre operazioni di scansione. 

La prima scansione accede a tutti gli elementi della tabella per confrontare i risultati con le altre operazioni di scansione. 

La seconda scansione utilizza il metodo [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#addNestedAttributeToProject(software.amazon.awssdk.enhanced.dynamodb.NestedAttributeName)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#addNestedAttributeToProject(software.amazon.awssdk.enhanced.dynamodb.NestedAttributeName))builder per restituire solo il `street` valore dell'attributo.

La terza operazione di scansione utilizza il metodo [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#attributesToProject(java.lang.String...)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#attributesToProject(java.lang.String...))builder per restituire i dati per l'attributo di primo livello,. `hobbies` Il tipo di attributo di `hobbies` è un elenco. Per accedere a singoli elementi dell'elenco, eseguire un'`get()`operazione sull'elenco.

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

**Nota**  
Se il `attributesToProject()` metodo segue qualsiasi altro metodo di creazione che aggiunge gli attributi che desiderate proiettare, l'elenco dei nomi degli attributi fornito `attributesToProject()` sostituisce tutti gli altri nomi di attributo.  
Una scansione eseguita con l'`ScanEnhancedRequest`istanza nel frammento seguente restituisce solo dati relativi agli hobby.  

```
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]}
```
Il seguente frammento di codice utilizza innanzitutto il metodo. `attributesToProject()` Questo ordinamento conserva tutti gli altri attributi richiesti.  

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

## Usa tipi complessi nelle espressioni
<a name="ddb-en-client-adv-features-nested-expressions"></a>

È possibile utilizzare tipi complessi nelle espressioni, ad esempio espressioni di filtro ed espressioni di condizione, utilizzando gli operatori di dereferenziamento per navigare nella struttura del tipo complesso. Per oggetti e mappe, usa `. (dot)` e per gli elementi dell'elenco `[n]` (parentesi quadre attorno al numero di sequenza dell'elemento). Non puoi fare riferimento ai singoli elementi di un set, ma puoi usare la [`contains`funzione](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions).

L'esempio seguente mostra due espressioni di filtro utilizzate nelle operazioni di scansione. Le espressioni di filtro specificano le condizioni di corrispondenza per gli elementi da inserire nei risultati. L'esempio utilizza e `Person` `Address` le `PhoneNumber` classi mostrate in precedenza.

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

### Metodo di supporto che popola la tabella
<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);
    }
```

### Rappresentazione JSON degli elementi del database
<a name="nested-attributes-expression-json-items"></a>

```
{
 "id": 1,
 "addresses": {
  "billing": {
   "city": "BillingTown1",
   "state": "BS1",
   "street": null,
   "zipCode": null
  },
  "mailing": {
   "city": "MailingTown1",
   "state": "MS1",
   "street": null,
   "zipCode": null
  }
 },
 "firstName": "FirstName1",
 "lastName": "LastName1",
 "phoneNumbers": [
  {
   "number": "111-111-1111",
   "type": "work"
  },
  {
   "number": "222-222-2222",
   "type": "home"
  }
 ]
}

{
 "id": 2,
 "addresses": {
  "billing": {
   "city": "BillingTown2",
   "state": "BS2",
   "street": null,
   "zipCode": null
  },
  "mailing": {
   "city": "MailingTown2",
   "state": "MS2",
   "street": null,
   "zipCode": null
  }
 },
 "firstName": "FirstName2",
 "lastName": "LastName2",
 "phoneNumbers": [
  {
   "number": "333-333-3333",
   "type": "work"
  },
  {
   "number": "444-444-4444",
   "type": "cell"
  }
 ]
}
```

## Aggiorna gli elementi che contengono tipi complessi
<a name="ddb-en-client-adv-features-nested-updates"></a>

Per aggiornare un elemento che contiene tipi complessi, sono disponibili due approcci di base:
+ Approccio 1: recupera prima l'elemento (utilizzando`getItem`), aggiorna l'oggetto, quindi chiama`DynamoDbTable#updateItem`.
+ Approccio 2: non recuperate l'elemento, ma create una nuova istanza, impostate le proprietà che desiderate aggiornare e inviate l'istanza `DynamoDbTable#updateItem` impostando il valore appropriato di. [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) Questo approccio non richiede il recupero dell'elemento prima di aggiornarlo.

Gli esempi mostrati in questa sezione utilizzano le `PhoneNumber` classi `Person``Address`, e mostrate in precedenza.

### Approccio di aggiornamento 1: recupera, quindi aggiorna
<a name="ddb-en-client-adv-features-nested-updates-retreive"></a>

Utilizzando questo approccio, vi assicurate che nessun dato vada perso durante l'aggiornamento. L'API DynamoDB Enhanced Client ricrea il bean con gli attributi dell'elemento salvato in DynamoDB, inclusi i valori di tipi complessi. È quindi necessario utilizzare i getter e i setter per aggiornare il bean. Lo svantaggio di questo approccio è il costo che si deve sostenere per recuperare prima l'articolo.

L'esempio seguente dimostra che non si perde alcun dato se si recupera l'elemento prima di aggiornarlo.

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

### Approccio di aggiornamento 2: utilizzare un `IgnoreNullsMode` enum senza prima recuperare l'elemento
<a name="ddb-en-client-adv-features-nested-updates-nullmode"></a>

Per aggiornare un elemento in DynamoDB, puoi fornire un nuovo oggetto con solo le proprietà che desideri aggiornare e lasciare gli altri valori come nulli. Con questo approccio, è necessario essere consapevoli di come i valori nulli nell'oggetto vengono trattati dall'SDK e di come è possibile controllarne il comportamento.

Per specificare quali proprietà con valori nulli vuoi che l'SDK ignori, fornisci un enum quando crei il. `IgnoreNullsMode` [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) Come esempio di utilizzo di uno dei valori enumerati, il frammento seguente utilizza la modalità. `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"
    }
  }
*/
```

[L'Amazon DynamoDB Developer Guide contiene ulteriori informazioni sulle espressioni di aggiornamento.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html)

#### Descrizioni delle opzioni `IgnoreNullsMode`
<a name="ignore-nulls-mode-descriptions"></a>
+ `IgnoreNullsMode.SCALAR_ONLY`- Utilizzate questa impostazione per aggiornare gli attributi scalari a qualsiasi livello. L'SDK crea un'istruzione di aggiornamento che invia solo attributi scalari non nulli a DynamoDB. L'SDK ignora gli attributi scalari con valori nulli di un bean o di una mappa, mantenendo il valore salvato in DynamoDB.

  Quando si aggiorna un attributo scalare di map o bean, la mappa deve già esistere in DynamoDB. Se aggiungi una mappa o un bean all'oggetto che non esiste già per l'oggetto in DynamoDB, ricevi `DynamoDbException` un messaggio con il *messaggio Il percorso del documento fornito nell'espressione di aggiornamento non è valido per l'aggiornamento*. È necessario utilizzare `MAPS_ONLY` la modalità per aggiungere un bean o una map a DynamoDB prima di aggiornare uno qualsiasi dei suoi attributi.
+ `IgnoreNullsMode.MAPS_ONLY`- Utilizzate questa impostazione per aggiungere o sostituire proprietà che sono un bean o una mappa. L'SDK sostituisce o aggiunge qualsiasi mappa o bean fornito nell'oggetto. Tutti i bean o le mappe che sono nulli nell'oggetto vengono ignorati, mantenendo la mappa esistente in DynamoDB.
+ `IgnoreNullsMode.DEFAULT`- Con questa impostazione, l'SDK non ignora mai i valori nulli. Gli attributi scalari a qualsiasi livello che sono nulli vengono aggiornati a null. L'SDK aggiorna qualsiasi proprietà bean, map, list o set con valori nulli nell'oggetto su null in DynamoDB. Quando si utilizza questa modalità, o non si fornisce una modalità poiché è la modalità predefinita, è necessario recuperare prima l'elemento in modo che i valori in DynamoDB non siano impostati su null forniti nell'oggetto per l'aggiornamento, a meno che non si intenda impostare i valori su null.

In tutte le modalità, se si fornisce un oggetto con un elenco o un set non nullo, l'elenco o il set viene salvato in DynamoDB. `updateItem` 

#### Perché le modalità?
<a name="ddb-en-client-adv-features-nested-updates-nullmodes-why"></a>

Quando fornisci un oggetto con un bean o una map al `updateItem` metodo, l'SDK non è in grado di stabilire se utilizzare i valori delle proprietà nel bean (o i valori di immissione nella mappa) per aggiornare l'elemento o se l'intero bean/map deve sostituire ciò che è stato salvato in DynamoDB.

Partendo dal nostro esempio precedente che mostra innanzitutto il recupero dell'elemento, proviamo ad aggiornare l'`city`attributo di without the retrieval. `mainAddress`

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

I due esempi seguenti mostrano gli usi di e dei valori enumerati`MAPS_ONLY`. `SCALAR_ONLY` `MAPS_ONLY`aggiunge una mappa e `SCALAR_ONLY` aggiorna una mappa.

##### `IgnoreNullsMode.MAPS_ONLY` Esempio
<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.
    }
```

Fate riferimento alla tabella seguente per vedere quali valori nulli vengono ignorati per ciascuna modalità. Spesso è possibile lavorare con entrambi`SCALAR_ONLY`, `MAPS_ONLY` tranne quando si lavora con bean o mappe.


**Quali proprietà con valori nulli nell'oggetto inviato vengono ignorate dall'SDK per `updateItem` ciascuna modalità?**  

| Tipo di proprietà | in modalità SCALAR\$1ONLY | in modalità MAPS\$1ONLY | in modalità DEFAULT | 
| --- | --- | --- | --- | 
| Scalare superiore | Sì  | Sì | No | 
| Bean o mappa | Sì  | Sì | No | 
| Valore scalare di un bean o di una voce di mappa | Sì1 | No2 | No | 
| Elenco o set | Sì  | Sì | No | 

1 Ciò presuppone che la mappa esista già in DynamoDB. Qualsiasi valore scalare, nullo o non nullo, del bean o della mappa fornito nell'oggetto per l'aggiornamento richiede che esista un percorso al valore in DynamoDB. L'SDK costruisce un percorso verso l'attributo utilizzando l'operatore di dereferenza prima di inviare la richiesta. `. (dot)`

2 Poiché si utilizza la `MAPS_ONLY` modalità per sostituire completamente o aggiungere un bean o una map, tutti i valori null nel bean o nella mappa vengono mantenuti nella mappa salvata in DynamoDB.

# Conserva gli oggetti vuoti con `@DynamoDbPreserveEmptyObject`
<a name="ddb-en-client-adv-features-empty"></a>

Se salvi un bean in Amazon DynamoDB con oggetti vuoti e desideri che l'SDK ricrei gli oggetti vuoti al momento del recupero, annota il getter del bean interno con. `@DynamoDbPreserveEmptyObject`

Per illustrare come funziona l'annotazione, l'esempio di codice utilizza i due bean seguenti.

## Fagioli di esempio
<a name="ddb-en-client-adv-features-empty-ex1"></a>

La seguente classe di dati contiene due `InnerBean` campi. Il metodo getter`getInnerBeanWithoutAnno()`, non è annotato con. `@DynamoDbPreserveEmptyObject` Il `getInnerBeanWithAnno()` metodo è annotato.

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

Le istanze della `InnerBean` classe seguente sono campi di `MyBean` e vengono inizializzate come oggetti vuoti nel codice di esempio.

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

Il seguente esempio di codice salva un `MyBean` oggetto con bean interni inizializzati in DynamoDB e quindi recupera l'elemento. L'output registrato mostra che non `innerBeanWithoutAnno` è stato inizializzato, ma è stato creato. `innerBeanWithAnno`

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

## Schema statico alternativo
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

È possibile utilizzare la seguente `StaticTableSchema` versione degli schemi delle tabelle al posto delle annotazioni sui bean.

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

# Evita di salvare gli attributi nulli degli oggetti annidati
<a name="ddb-en-client-adv-features-ignore-null"></a>

È possibile ignorare gli attributi nulli degli oggetti nidificati quando si salva un oggetto di classe di dati in DynamoDB applicando l'annotazione. `@DynamoDbIgnoreNulls` Al contrario, gli attributi di primo livello con valori nulli non vengono mai salvati nel database.

Per illustrare come funziona l'annotazione, l'esempio di codice utilizza i due bean seguenti.

## Fagioli di esempio
<a name="ddb-en-client-adv-features-ignore-null-ex1"></a>

La seguente classe di dati contiene due `InnerBean` campi. Il metodo getter`getInnerBeanWithoutAnno()`, non è annotato. Il `getInnerBeanWithIgnoreNullsAnno()` metodo è annotato con. `@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();
    }
}
```

Le istanze della seguente `InnerBean` classe sono campi di `MyBean` e vengono utilizzate nel seguente codice di esempio.

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

Il seguente esempio di codice crea un `InnerBean` oggetto e imposta solo uno dei suoi due attributi con un valore. 

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

Per visualizzare i dati di basso livello inviati a DynamoDB, il codice registra la mappa degli attributi prima di salvare l'oggetto. `MyBean`

L'output registrato mostra che restituisce un attributo, `innerBeanWithIgnoreNullsAnno`

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

L'`innerBeanWithoutAnno`istanza restituisce due attributi. Un attributo ha un valore di 200 e l'altro è un attributo con valore nullo.

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

## Rappresentazione JSON della mappa degli attributi
<a name="ddb-en-client-adv-features-ignore-null-ex2"></a>

La seguente rappresentazione JSON semplifica la visualizzazione dei dati salvati in DynamoDB.

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

## Schema statico alternativo
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

È possibile utilizzare la seguente `StaticTableSchema` versione degli schemi delle tabelle al posto delle annotazioni delle classi di dati.

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

# Lavora con documenti JSON con l'API Enhanced Document per DynamoDB
<a name="ddb-en-client-doc-api"></a>

L'[Enhanced Document API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) for AWS SDK for Java 2.x è progettata per funzionare con dati orientati ai documenti che non hanno uno schema fisso. Tuttavia, consente anche di utilizzare classi personalizzate per mappare singoli attributi.

 L'Enhanced Document API è il successore dell'[API Document](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html) della AWS SDK per Java versione 1.x.

**Contents**
+ [Inizia a usare l'Enhanced Document API](ddb-en-client-doc-api-steps.md)
  + [Crea un e un `DocumentTableSchema` `DynamoDbTable`](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema)
+ [Crea documenti avanzati](ddb-en-client-doc-api-steps-create-ed.md)
  + [Crea da una stringa JSON](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromJson)
  + [Costruisci a partire da singoli elementi](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts)
+ [Esegui operazioni CRUD](ddb-en-client-doc-api-steps-use.md)
+ [Accedi agli attributi avanzati del documento come oggetti personalizzati](ddb-en-client-doc-api-convert.md)
+ [Usa e `EnhancedDocument` senza DynamoDB](ddb-en-client-doc-api-standalone.md)

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

L'API Enhanced Document richiede le stesse [dipendenze](ddb-en-client-getting-started.md#ddb-en-client-gs-dep) necessarie per l'API DynamoDB Enhanced Client. Richiede anche un'[`DynamoDbEnhancedClient`istanza](ddb-en-client-getting-started-dynamodbTable.md#ddb-en-client-getting-started-dynamodbTable-eclient), come mostrato all'inizio di questo argomento.

Poiché l'Enhanced Document API è stata rilasciata con la versione 2.20.3 di AWS SDK for Java 2.x, è necessaria quella versione o superiore.

## Crea un e un `DocumentTableSchema` `DynamoDbTable`
<a name="ddb-en-client-doc-api-steps-createschema"></a>

Per richiamare comandi su una tabella DynamoDB utilizzando l'API Enhanced Document, associa la tabella a un oggetto risorsa < > lato [DynamoDbTableclient EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html). 

Il `table()` metodo del client avanzato crea un'`DynamoDbTable<EnhancedDocument>`istanza e richiede parametri per il nome della tabella DynamoDB e un. `DocumentTableSchema` 

Il builder for a [DocumentTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/DocumentTableSchema.html)richiede una chiave di indice principale e uno o più provider di convertitori di attributi. Il `AttributeConverterProvider.defaultProvider()` metodo fornisce convertitori per i tipi [predefiniti](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/package-summary.html). Dovrebbe essere specificato anche se si fornisce un provider di convertitori di attributi personalizzato. È possibile aggiungere una chiave di indice secondaria opzionale al generatore.

Il seguente frammento di codice mostra il codice che genera la rappresentazione lato client di una tabella DynamoDB che memorizza oggetti senza schema. `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.
```

Di seguito viene illustrata la rappresentazione JSON di un oggetto utilizzata in questa sezione. `person`

### Oggetto JSON `person`
<a name="ddb-en-client-doc-api-steps-createschema-obj"></a>

```
{
  "id": 1,
  "firstName": "Richard",
  "lastName": "Roe",
  "age": 25,
  "addresses":
    {
      "home": {
        "zipCode": "00000",
        "city": "Any Town",
        "state": "FL",
        "street": "123 Any Street"
      },
      "work": {
        "zipCode": "00001",
        "city": "Anywhere",
        "state": "FL",
        "street": "100 Main Street"
      }
    },
  "hobbies": [
    "Hobby 1",
    "Hobby 2"
  ],
  "phoneNumbers": [
    {
      "type": "Home",
      "number": "555-0100"
    },
    {
      "type": "Work",
      "number": "555-0119"
    }
  ]
}
```

# Crea documenti avanzati
<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)` rappresenta un oggetto di tipo documento con una struttura complessa con attributi annidati. An `EnhancedDocument` richiede attributi di primo livello che corrispondano agli attributi della chiave primaria specificati per. `DocumentTableSchema` Il contenuto rimanente è arbitrario e può essere costituito da attributi di primo livello e anche da attributi profondamente annidati.

Si crea un'`EnhancedDocument`istanza utilizzando un generatore che offre diversi modi per aggiungere elementi.

## Crea da una stringa JSON
<a name="ddb-en-client-doc-api-steps-create-ed-fromJson"></a>

Con una stringa JSON, puoi creare una chiamata `EnhancedDocument` in un unico metodo. Il seguente frammento crea un `EnhancedDocument` da una stringa JSON restituita dal metodo helper. `jsonPerson()` [Il `jsonPerson()` metodo restituisce la versione in stringa JSON dell'oggetto persona mostrato in precedenza.](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema-obj)

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

## Costruisci a partire da singoli elementi
<a name="ddb-en-client-doc-api-steps-create-ed-fromparts"></a>

In alternativa, puoi creare un'`EnhancedDocument`istanza a partire da singoli componenti utilizzando i metodi type-safe del builder.

L'esempio seguente crea un documento `person` avanzato simile al documento avanzato creato a partire dalla stringa JSON dell'esempio precedente.

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

### Metodi di supporto
<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"));

    }
```

# Esegui operazioni CRUD
<a name="ddb-en-client-doc-api-steps-use"></a>

Dopo aver definito un'`EnhancedDocument`istanza, è possibile salvarla in una tabella DynamoDB. Il seguente frammento di codice utilizza [PersonDocument creato](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts) da singoli elementi.

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

Dopo aver letto un'istanza di documento avanzata da DynamoDB, è possibile estrarre i valori dei singoli attributi utilizzando i getter, come mostrato nel seguente frammento di codice, che accedono ai dati salvati da. `personDocument` In alternativa, è possibile estrarre il contenuto completo in una stringa JSON, come mostrato nell'ultima parte del codice di esempio.

```
        // 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`le istanze possono essere utilizzate con qualsiasi metodo `[DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)` o al posto delle classi [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html)di dati mappate.

# Accedi agli attributi avanzati del documento come oggetti personalizzati
<a name="ddb-en-client-doc-api-convert"></a>

Oltre a fornire un'API per leggere e scrivere attributi con strutture senza schema, l'API Enhanced Document consente di convertire gli attributi da e verso istanze di classi personalizzate.

L'API Enhanced Document utilizza `AttributeConverterProvider` i `AttributeConverter` caratteri e i caratteri mostrati nella sezione di [conversione degli attributi di controllo](ddb-en-client-adv-features-conversion.md) come parte dell'API DynamoDB Enhanced Client.

Nell'esempio seguente, utilizziamo a `CustomAttributeConverterProvider` con la sua `AddressConverter` classe annidata per convertire gli oggetti. `Address` 

Questo esempio mostra che è possibile combinare dati provenienti da classi e anche dati provenienti da strutture create secondo necessità. Questo esempio mostra anche che le classi personalizzate possono essere utilizzate a qualsiasi livello di una struttura annidata. Gli `Address` oggetti in questo esempio sono valori utilizzati in una mappa.

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

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

## Metodo di supporto che fornisce indirizzi
<a name="ddb-en-client-doc-api-convert-helper"></a>

Il seguente metodo di supporto fornisce la mappa che utilizza istanze personalizzate per i valori anziché `Address` istanze generiche `Map<String, String>` per i valori.

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

# Usa e `EnhancedDocument` senza DynamoDB
<a name="ddb-en-client-doc-api-standalone"></a>

Sebbene di solito si utilizzi un'istanza di an `EnhancedDocument` per leggere e scrivere elementi DynamoDB di tipo documento, può essere utilizzata anche indipendentemente da DynamoDB. 

È possibile utilizzarli `EnhancedDocuments` per la loro capacità di convertire tra stringhe JSON o oggetti personalizzati in mappe di basso livello come mostrato nell'esempio seguente. `AttributeValues`

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

**Nota**  
Quando utilizzi un documento avanzato indipendente da una tabella DynamoDB, assicurati di impostare in modo esplicito i provider di conversione degli attributi sul builder.  
Al contrario, lo schema della tabella dei documenti fornisce i provider di conversione quando un documento avanzato viene utilizzato con una tabella DynamoDB.

# Usa le estensioni per personalizzare le operazioni di DynamoDB Enhanced Client
<a name="ddb-en-client-extensions"></a>

L'API DynamoDB Enhanced Client supporta le estensioni dei plugin che forniscono funzionalità che vanno oltre le operazioni di mappatura. Le estensioni utilizzano due metodi hook per modificare i dati durante le operazioni di lettura e scrittura:
+ `beforeWrite()`- Modifica un'operazione di scrittura prima che avvenga
+ `afterRead()`- Modifica i risultati di un'operazione di lettura dopo che è avvenuta

Alcune operazioni (come l'aggiornamento degli elementi) eseguono sia una scrittura che una lettura, quindi vengono chiamati entrambi i metodi hook.

## Come vengono caricate le estensioni
<a name="ddb-en-client-extensions-loading"></a>

Le estensioni vengono caricate nell'ordine specificato nel generatore di client avanzato. L'ordine di caricamento può essere importante perché un'estensione può agire su valori che sono stati trasformati da un'estensione precedente.

Per impostazione predefinita, il client avanzato carica due estensioni:
+ `[VersionedRecordExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtension.html)`- Fornisce un blocco ottimistico
+ `[AtomicCounterExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/AtomicCounterExtension.html)`- Incrementa automaticamente gli attributi del contatore

È possibile sovrascrivere il comportamento predefinito con il client builder avanzato e caricare qualsiasi estensione. Puoi anche specificarne nessuna se non desideri le estensioni predefinite.

**Importante**  
Se carichi le tue estensioni, il client avanzato non carica alcuna estensione predefinita. Se desideri il comportamento fornito da una delle estensioni predefinite, devi aggiungerla esplicitamente all'elenco delle estensioni.

L'esempio seguente mostra come caricare un'estensione personalizzata che `verifyChecksumExtension` prende il `VersionedRecordExtension` nome da. In questo esempio non `AtomicCounterExtension` viene caricato.

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

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

## Dettagli e configurazione delle estensioni disponibili
<a name="ddb-en-client-extensions-details"></a>

Le seguenti sezioni forniscono informazioni dettagliate su ciascuna estensione disponibile nell'SDK.

### Implementa il blocco ottimistico con `VersionedRecordExtension`
<a name="ddb-en-client-extensions-VRE"></a>

L'`VersionedRecordExtension`estensione fornisce un blocco ottimistico incrementando e tracciando il numero di versione di un articolo man mano che gli articoli vengono scritti nel database. A ogni scrittura viene aggiunta una condizione che causa l'esito negativo della scrittura se il numero di versione dell'elemento persistente effettivo non corrisponde al valore letto per l'ultima volta dall'applicazione.

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

Per specificare l'attributo da utilizzare per tenere traccia del numero di versione dell'elemento, contrassegnate un attributo numerico nello schema della tabella.

Il frammento seguente specifica che l'`version`attributo deve contenere il numero di versione dell'articolo.

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

L'approccio equivalente allo schema di tabella statica è illustrato nel frammento seguente.

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

#### Come funziona
<a name="ddb-en-client-extensions-VRE-how-it-works"></a>

Il blocco ottimistico con il `VersionedRecordExtension` ha il seguente impatto su questi metodi: `DynamoDbEnhancedClient` `DynamoDbTable`

**`putItem`**  
Ai nuovi elementi viene assegnato un valore di versione iniziale pari a 0. Questo può essere configurato con`@DynamoDbVersionAttribute(startAt = X)`.

**`updateItem`**  
Se recuperate un elemento, aggiornate una o più delle sue proprietà e tentate di salvare le modifiche, l'operazione ha esito positivo solo se il numero di versione sul lato client e sul lato server corrisponde.  
In caso di successo, il numero di versione viene automaticamente incrementato di 1. Questo può essere configurato con`@DynamoDbVersionAttribute(incrementBy = X)`.

**`deleteItem`**  
L'`DynamoDbVersionAttribute`annotazione non ha effetto. È necessario aggiungere manualmente un'espressione di condizione quando si elimina un elemento.  
L'esempio seguente aggiunge un'espressione condizionale per garantire che l'elemento eliminato sia quello che è stato letto. Nell'esempio seguente l'attributo del bean `recordVersion` è annotato con. `@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`: Questo metodo ha lo stesso comportamento di`putItem`.
+ `addUpdateItem`: Questo metodo ha lo stesso comportamento di`updateItem`.
+ `addDeleteItem`: Questo metodo ha lo stesso comportamento di`deleteItem`.

**`batchWriteItem`**  
+ `addPutItem`: Questo metodo ha lo stesso comportamento di`putItem`.
+ `addDeleteItem`: Questo metodo ha lo stesso comportamento di`deleteItem`.

**Nota**  
Le tabelle globali di DynamoDB utilizzano [una riconciliazione «last writer win»](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/V2globaltables_HowItWorks.html#V2globaltables_HowItWorks.consistency-modes) tra aggiornamenti simultanei, in cui DynamoDB fa del suo meglio per determinare l'ultimo writer. Se si utilizzano tabelle globali, questa politica «l'ultimo scrittore vince» significa che le strategie di blocco potrebbero non funzionare come previsto, poiché tutte le repliche alla fine convergeranno in base all'ultima scrittura determinata da DynamoDB. 

#### Come disattivare
<a name="ddb-en-client-extensions-VRE-how-to-disable"></a>

Per disabilitare il blocco ottimistico, non utilizzare l'`@DynamoDbVersionAttribute`annotazione.

### Implementa i contatori con `AtomicCounterExtension`
<a name="ddb-en-client-extensions-ACE"></a>

L'`AtomicCounterExtension`estensione incrementa un attributo numerico con tag ogni volta che un record viene scritto nel database. È possibile specificare valori iniziali e incrementali. Se non viene specificato alcun valore, il valore iniziale viene impostato su 0 e il valore dell'attributo aumenta di 1.

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

Per specificare quale attributo è un contatore, contrassegnate un attributo di tipo `Long` nello schema della tabella.

Il frammento seguente mostra l'uso dei valori di inizio e incremento predefiniti per l'attributo. `counter`

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

L'approccio allo schema di tabella statica è illustrato nel frammento seguente. L'estensione del contatore atomico utilizza un valore iniziale di 10 e incrementa il valore di 5 ogni volta che viene scritto il record.

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

### Aggiungi timestamp con `AutoGeneratedTimestampRecordExtension`
<a name="ddb-en-client-extensions-AGTE"></a>

L'`AutoGeneratedTimestampRecordExtension`estensione aggiorna automaticamente gli attributi di tipo contrassegnati `[Instant](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html)` con un timestamp corrente ogni volta che l'elemento viene scritto correttamente nel database. Questa estensione non viene caricata per impostazione predefinita.

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

Per specificare l'attributo da aggiornare con il timestamp corrente, contrassegnate l'`Instant`attributo nello schema della tabella.

L'`lastUpdate`attributo è l'obiettivo del comportamento dell'estensione nel frammento seguente. Nota il requisito secondo cui l'attributo deve essere di `Instant` tipo.

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

L'approccio equivalente allo schema di tabella statica è illustrato nel frammento seguente.

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

### Genera un UUID con AutoGeneratedUuidExtension
<a name="ddb-en-client-extensions-AGUE"></a>

L'`AutoGeneratedUuidExtension`estensione genera un UUID (Universally Unique Identifier) univoco per un attributo quando un nuovo record viene scritto nel database. Utilizza il metodo Java JDK [UUID.randomUUID](https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html#randomUUID--) () e si applica agli attributi di tipo. `java.lang.String` Questa estensione non viene caricata per impostazione predefinita.

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

L'`uniqueId`attributo è l'obiettivo del comportamento dell'estensione nel frammento seguente.

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

L'approccio equivalente allo schema di tabella statica è illustrato nel frammento seguente.

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

Se desideri che l'estensione compili l'UUID solo per i `putItem` metodi e non per i `updateItem` metodi, aggiungi l'annotazione sul [comportamento di aggiornamento](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html) come mostrato nel seguente frammento.

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

Se utilizzate l'approccio dello schema a tabella statica, utilizzate il seguente codice equivalente.

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

# Esempio di estensione personalizzata
<a name="ddb-en-client-extensions-custom"></a>

È possibile creare estensioni personalizzate implementando l'`DynamoDbEnhancedClientExtension`interfaccia. La seguente classe di estensione personalizzata mostra un `beforeWrite()` metodo che utilizza un'espressione di aggiornamento per impostare un `registrationDate` attributo se l'elemento nel database non ne ha già uno.

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

# Usa l'API DynamoDB Enhanced Client in modo asincrono
<a name="ddb-en-client-async"></a>

Se l'applicazione richiede chiamate asincrone non bloccanti a DynamoDB, è possibile utilizzare il. [DynamoDbEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html) È simile all'implementazione sincrona ma con le seguenti differenze chiave:

1. Quando si crea il`DynamoDbEnhancedAsyncClient`, è necessario fornire la versione asincrona del client standard`DynamoDbAsyncClient`, come mostrato nel frammento seguente.

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

1. I metodi che restituiscono un singolo oggetto di dati restituiscono un `CompletableFuture` risultato anziché solo il risultato. L'applicazione può quindi eseguire altre operazioni senza dover bloccare il risultato. Il frammento seguente mostra il metodo `getItem()` asincrono. 

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

1. I metodi che restituiscono elenchi di risultati impaginati restituiscono un valore [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)anziché un valore restituito dalla modalità sincrona per [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)gli stessi metodi. `DynamoDbEnhanceClient` L'applicazione può quindi sottoscrivere un gestore a tale editore per gestire i risultati in modo asincrono senza dover bloccare.

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

   Per un esempio più completo di utilizzo di`SdkPublisher API`, consultate l'[esempio](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-scan-async) nella sezione che illustra il metodo `scan()` asincrono di questa guida.

# Annotazioni di classi di dati
<a name="ddb-en-client-anno-index"></a>

La tabella seguente elenca le annotazioni che possono essere utilizzate sulle classi di dati e fornisce collegamenti a informazioni ed esempi contenuti in questa guida. La tabella è ordinata in ordine alfabetico crescente in base al nome dell'annotazione.


**Annotazioni delle classi di dati utilizzate in questa guida**  

| Nome dell'annotazione | L'annotazione si applica a 1 | Cosa fa | Dove viene mostrato in questa guida | 
| --- | --- | --- | --- | 
| DynamoDbAtomicCounter | attributo 2 | Incrementa un attributo numerico con tag ogni volta che un record viene scritto nel database. | [Introduzione e discussione.](ddb-en-client-extensions.md#ddb-en-client-extensions-ACE) | 
| DynamoDbAttribute | attributo | Definisce o rinomina una proprietà del bean mappata a un attributo di tabella DynamoDB. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbAutoGeneratedTimestampAttribute | attributo | Aggiorna un attributo taggato con un timestamp corrente ogni volta che l'elemento viene scritto correttamente nel database | [Introduzione e discussione.](ddb-en-client-extensions.md#ddb-en-client-extensions-AGTE) | 
| DynamoDbAutoGeneratedUuid | attributo | Genera un UUID (Universally Unique Identifier) univoco per un attributo quando un nuovo record viene scritto nel database. | [Introduzione e discussione.](ddb-en-client-extensions.md#ddb-en-client-extensions-AGUE) | 
| DynamoDbBean | classe | Contrassegna una classe di dati come mappabile su uno schema tabellare. | Primo utilizzo sulla [classe Customer nella sezione](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) Guida introduttiva. In tutta la guida sono presenti diversi utilizzi. | 
| DynamoDbConvertedBy | attributo | Associa un attributo personalizzato all'AttributeConverterattributo annotato. | [Discussione iniziale ed esempio.](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-single) | 
| DynamoDbFlatten | attributo | Appiattisce tutti gli attributi di una classe di dati DynamoDB separata e li aggiunge come attributi di primo livello al record che viene letto e scritto nel database.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnore | attributo |  Fa sì che l'attributo rimanga non mappato.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnoreNulls | attributo | Impedisce il salvataggio degli attributi nulli degli oggetti annidati. DynamoDb  | [Discussioni ed esempi.](ddb-en-client-adv-features-ignore-null.md) | 
| DynamoDbImmutable | classe |  Contrassegna una classe di dati immutabile come mappabile su uno schema tabellare.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPartitionKey | attributo |  Contrassegna un attributo come chiave di partizione primaria (chiave hash) della tabella. DynamoDb  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPreserveEmptyObject | attributo |  Speciifica che se non sono presenti dati per l'oggetto mappato all'attributo annotato, l'oggetto deve essere inizializzato con tutti i campi nulli.  | [Discussione ed esempi.](ddb-en-client-adv-features-empty.md) | 
| DynamoDbSecondaryPartitionKey | attributo |  Contrassegna un attributo come chiave di partizione per un indice secondario globale.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSecondarySortKey | attributo |  Contrassegna un attributo come chiave di ordinamento opzionale per un indice secondario globale o locale.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSortKey | attributo |  Contrassegna un attributo come chiave di ordinamento primaria opzionale (chiave di intervallo).  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbUpdateBehavior | attributo |  Specifica il comportamento quando questo attributo viene aggiornato come parte di un'operazione di 'aggiornamento' come UpdateItem.  | [Introduzione ed esempio.](ddb-en-client-adv-features-upd-behavior.md) | 
| DynamoDbVersionAttribute | attributo | Incrementa il numero di versione di un articolo. | [Introduzione e discussione.](ddb-en-client-extensions.md#ddb-en-client-extensions-VRE) | 

1 È possibile applicare un'annotazione a livello di attributo al getter o al setter, ma non a entrambi. Questa guida mostra le annotazioni sui getter.

2 Il termine `property` viene normalmente utilizzato per un valore incapsulato in una classe di dati. JavaBean Tuttavia, questa guida utilizza `attribute` invece il termine, per coerenza con la terminologia utilizzata da DynamoDB.