Avvio rapido: Creare un'API per l'app Table con Node.js e Azure Cosmos DB

SI APPLICA A: Tabella

Questo argomento di avvio rapido illustra come accedere all'API Table di Azure Cosmos DB da un'applicazione Java. L'API Table di Azure Cosmos DB è un archivio dati senza schema che consente alle applicazioni di archiviare dati NoSQL strutturati nel cloud. Poiché i dati vengono archiviati in una struttura senza schema, nuove proprietà (colonne) vengono automaticamente aggiunte alla tabella ogni volta che ad essa viene aggiunto un oggetto con un nuovo attributo.

Per accedere all'API Table di Azure Cosmos DB da un'applicazione Java, usare la libreria client azure-data-tables.

Prerequisiti

L'applicazione di esempio è scritta in Spring Boot 2.6.4. Come ambiente di sviluppo integrato è possibile usare Visual Studio Codeo IntelliJ IDEA.

Se non si ha una sottoscrizione di Azure, creare un account gratuito prima di iniziare.

Applicazione di esempio

L'applicazione di esempio per questa esercitazione può essere clonata o scaricata dal repository https://github.com/Azure-Samples/msdocs-azure-data-tables-sdk-java. Nel repository di esempio sono incluse sia un'app di partenza che l'app completata.

git clone https://github.com/Azure-Samples/msdocs-azure-data-tables-sdk-java

L'applicazione di esempio usa dati meteo come esempio per illustrare le funzionalità dell'API Table. Gli oggetti che rappresentano le osservazioni meteo vengono archiviati e recuperati usando l'API Table; vengono archiviati anche oggetti con proprietà aggiuntive per illustrare le funzionalità senza schema dell'API Table.

A screenshot of the finished application showing data stored in an Azure Cosmos DB table using the Table API.

1 - Creare un account Azure Cosmos DB

È prima necessario creare un account dell'API Table di Azure Cosmos DB che conterrà le tabelle usate nell'applicazione. Questa operazione può essere eseguita usando il portale di Azure, l'interfaccia della riga di comando di Azure o Azure PowerShell.

Per creare un account Azure Cosmos DB, accedere al portale di Azure e seguire questa procedura.

Istruzioni Schermata
Nel portale di Azure:
  1. Nella casella di ricerca nella parte superiore del portale di Azure immettere "Azure Cosmos DB".
  2. Nel menu visualizzato sotto la barra di ricerca, nell'area Servizi, selezionare l'elemento etichettato Azure Cosmos DB.
A screenshot showing how to use the search box in the top tool bar to find Azure Cosmos DB accounts in Azure.
Nella pagina Azure Cosmos DB selezionare Crea. A screenshot showing the Create button location on the Azure Cosmos DB accounts page in Azure.
Nella pagina Seleziona l'opzione API scegliere l'opzione Azure Table. A screenshot showing the Azure Table option as the correct option to select.
Nella pagina Crea account Azure Cosmos DB - Azure Table compilare il modulo come indicato di seguito.
  1. Creare un nuovo gruppo di risorse per l'account di archiviazione denominato rg-msdocs-tables-sdk-demo selezionando il collegamento Crea nuovo in Gruppo di risorse.
  2. Assegnare all'account di archiviazione il nome cosmos-msdocs-tables-sdk-demo-XYZ, in cui XYZ è costituito da tre caratteri casuali per creare un nome di account univoco. I nomi degli account Azure Cosmos DB devono avere una lunghezza compresa tra 3 e 44 caratteri e possono contenere solo lettere minuscole, numeri o il segno meno (-).
  3. Selezionare l'area per l'account di archiviazione.
  4. Selezionare le prestazioni Standard.
  5. Ai fini di questo esempio, per Velocità effettiva con provisioning selezionare Modalità capacità.
  6. Ai fini di questo esempio, selezionare Applica nell'area Applica sconto per il livello gratuito.
  7. Selezionare il pulsante Rivedi e crea nella parte inferiore della schermata e quindi scegliere "Crea" nella schermata di riepilogo per creare l'account Azure Cosmos DB. Questo processo potrebbe richiedere alcuni minuti.
A screenshot showing how to fill out the fields on the Azure Cosmos DB Account creation page.

2 - Creare una tabella

A questo punto, è necessario creare una tabella all'interno dell'account Azure Cosmos DB da usare per l'applicazione. A differenza di un database tradizionale, è necessario specificare solo il nome della tabella, non le proprietà (colonne) della tabella. Le proprietà (colonne) vengono create automaticamente nel momento in cui i dati vengono caricati nella tabella.

Nel portale di Azure completare la procedura seguente per creare una tabella all'interno dell'account Azure Cosmos DB.

Istruzioni Schermata
Nel portale di Azure passare alla pagina Panoramica dell'account Azure Cosmos DB. È possibile passare alla pagina di panoramica per l'account Azure Cosmos DB digitando il nome (cosmos-msdocs-tables-sdk-demo-XYZ) dell'account Azure Cosmos DB nella barra di ricerca superiore e cercando la voce desiderata sotto l'intestazione delle risorse. Selezionare il nome dell'account Azure Cosmos DB per passare alla pagina Panoramica. A screenshot showing how to use the search box in the top tool bar to find your Azure Cosmos DB account.
Nella pagina di panoramica selezionare Aggiungi tabella. Sul lato destro della pagina viene visualizzata la finestra di dialogo Nuova tabella. A screenshot showing the location of the Add Table button.
Nella finestra di dialogo Nuova tabella compilare il modulo come indicato di seguito.
  1. Nel campo dell'ID tabella immettere il nome WeatherData, che diventa il nome della tabella.
  2. Ai fini di questo esempio, selezionare Manuale nell'area Velocità effettiva tabella (scalabilità automatica).
  3. Usare il valore predefinito 400 nel campo delle UR/sec stimate.
  4. Scegliere il pulsante OK per creare la tabella.
A screenshot showing how to New Table dialog box for an Azure Cosmos DB table.

3 - Ottenere la stringa di connessione di Azure Cosmos DB

Per accedere alle tabelle in Azure Cosmos DB, l'app richiederà la stringa di connessione della tabella per l'account Cosmos DB Storage. La stringa di connessione può essere recuperata usando il portale di Azure, l'interfaccia della riga di comando di Azure o Azure PowerShell.

Istruzioni Schermata
Sul lato sinistro della pagina dell'account Azure Cosmos DB individuare la voce di menu denominata Stringa di connessione sotto l'intestazione Impostazioni e selezionarla. Verrà visualizzata una pagina in cui è possibile recuperare la stringa di connessione per l'account di archiviazione. A screenshot showing the location of the connection strings link on the Azure Cosmos DB page.
Copiare il valore PRIMARY CONNECTION STRING da usare nell'applicazione. A screenshot showing the which connection string to select and use in your application.

La stringa di connessione per l'account Azure Cosmos DB è considerata un segreto dell'app e deve essere protetta come qualsiasi altro segreto o password dell'app. In questo esempio viene usato POM per archiviare la stringa di connessione durante lo sviluppo e renderla disponibile all'applicazione.

<profiles>
    <profile>
        <id>local</id>
        <properties>
            <azure.tables.connection.string>
                <![CDATA[YOUR-DATA-TABLES-SERVICE-CONNECTION-STRING]]>
            </azure.tables.connection.string>
            <azure.tables.tableName>WeatherData</azure.tables.tableName>
        </properties>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
</profiles>

4 - Includere il pacchetto azure-data-tables

Per accedere all'API Table di Azure Cosmos DB da un'applicazione Java, includere il pacchetto azure-data-tables.

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-data-tables</artifactId>
    <version>12.2.1</version>
</dependency>

5 - Configurare il client Table in TableServiceConfig.java

Azure SDK comunica con Azure usando oggetti client per eseguire diverse operazioni in Azure. L'oggetto TableClient è l'oggetto usato per comunicare con l'API Table di Azure Cosmos DB.

Un'applicazione crea in genere un solo oggetto TableClient per tabella da usare in tutta l'applicazione. È consigliabile indicare che un metodo produce un bean dell'oggetto TableClient da gestire con il contenitore Spring e come singleton per eseguire questa operazione.

Nel file TableServiceConfig.java dell'applicazione modificare il metodo tableClientConfiguration() in modo che corrisponda al frammento di codice seguente:

@Configuration
public class TableServiceConfiguration {

    private static String TABLE_NAME;

    private static String CONNECTION_STRING;

    @Value("${azure.tables.connection.string}")
    public void setConnectionStringStatic(String connectionString) {
        TableServiceConfiguration.CONNECTION_STRING = connectionString;
    }

    @Value("${azure.tables.tableName}")
    public void setTableNameStatic(String tableName) {
        TableServiceConfiguration.TABLE_NAME = tableName;
    }

    @Bean
    public TableClient tableClientConfiguration() {
        return new TableClientBuilder()
                .connectionString(CONNECTION_STRING)
                .tableName(TABLE_NAME)
                .buildClient();
    }
    
}

Sarà inoltre necessario aggiungere l'istruzione using seguente all'inizio del file TableServiceConfig.java.

import com.azure.data.tables.TableClient;
import com.azure.data.tables.TableClientBuilder;

6 - Implementare operazioni di tabella in Azure Cosmos DB

Tutte le operazioni di tabella di Azure Cosmos DB per l'app di esempio vengono implementate nella classe TablesServiceImpl che si trova nella directory Servizi. È necessario importare il pacchetto SDK com.azure.data.tables.

import com.azure.data.tables.TableClient;
import com.azure.data.tables.models.ListEntitiesOptions;
import com.azure.data.tables.models.TableEntity;
import com.azure.data.tables.models.TableTransactionAction;
import com.azure.data.tables.models.TableTransactionActionType;

All'inizio della classe TableServiceImpl aggiungere una variabile membro per l'oggetto TableClient e un costruttore per consentire l'inserimento dell'oggetto TableClient nella classe.

@Autowired
private TableClient tableClient;

Ottenere righe da una tabella

La classe TableClient contiene un metodo denominato listEntities che consente di selezionare alcune righe della tabella. In questo esempio, poiché non vengono passati parametri al metodo, tutte le righe verranno selezionate dalla tabella.

Il metodo accetta anche un parametro generico di tipo TableEntity che specifica la classe di modello in cui verranno restituiti i dati. In questo caso, viene usata la classe predefinita TableEntity, ovvero il metodo listEntities restituirà una raccolta PagedIterable<TableEntity> come risultati.

public List<WeatherDataModel> retrieveAllEntities() {
    List<WeatherDataModel> modelList = tableClient.listEntities().stream()
        .map(WeatherDataUtils::mapTableEntityToWeatherDataModel)
        .collect(Collectors.toList());
    return Collections.unmodifiableList(WeatherDataUtils.filledValue(modelList));
}

La classe TableEntity definita nel pacchetto com.azure.data.tables.models dispone di proprietà per i valori di chiave di partizione e chiave di riga presenti nella tabella. Insieme, questi due valori costituiscono una chiave univoca per la riga della tabella. In questa applicazione di esempio, il nome della stazione meteo (città) viene archiviato nella chiave di partizione, mentre la data/ora dell'osservazione viene archiviata nella chiave di riga. Tutte le altre proprietà (temperatura, umidità, velocità del vento) vengono archiviate in un dizionario nell'oggetto TableEntity.

È pratica comune eseguire il mapping di un oggetto TableEntity a un oggetto della propria definizione. A questo scopo, l'applicazione di esempio definisce una classe WeatherDataModel nella directory Modelli. Questa classe ha proprietà per il nome della stazione e la data di osservazione a cui verrà eseguito il mapping della chiave di partizione e della chiave di riga, fornendo nomi di proprietà più significativi per questi valori. Usa quindi un dizionario per archiviare tutte le altre proprietà nell'oggetto. Si tratta di un modello comune quando si usa Table Storage perché una riga può avere un qualsiasi numero di proprietà arbitrarie e si vuole che gli oggetti modello siano in grado di acquisirle tutte. Questa classe contiene anche alcuni metodi per elencare le proprietà nella classe.

public class WeatherDataModel {

    public WeatherDataModel(String stationName, String observationDate, OffsetDateTime timestamp, String etag) {
        this.stationName = stationName;
        this.observationDate = observationDate;
        this.timestamp = timestamp;
        this.etag = etag;
    }

    private String stationName;

    private String observationDate;

    private OffsetDateTime timestamp;

    private String etag;

    private Map<String, Object> propertyMap = new HashMap<String, Object>();

    public String getStationName() {
        return stationName;
    }

    public void setStationName(String stationName) {
        this.stationName = stationName;
    }

    public String getObservationDate() {
        return observationDate;
    }

    public void setObservationDate(String observationDate) {
        this.observationDate = observationDate;
    }

    public OffsetDateTime getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(OffsetDateTime timestamp) {
        this.timestamp = timestamp;
    }

    public String getEtag() {
        return etag;
    }

    public void setEtag(String etag) {
        this.etag = etag;
    }

    public Map<String, Object> getPropertyMap() {
        return propertyMap;
    }

    public void setPropertyMap(Map<String, Object> propertyMap) {
        this.propertyMap = propertyMap;
    }
}

Il metodo mapTableEntityToWeatherDataModel consente di eseguire il mapping di un oggetto TableEntity a un oggetto WeatherDataModel. Il metodo mapTableEntityToWeatherDataModel esegue direttamente il mapping delle proprietà PartitionKey, RowKey, Timestamp e Etag e quindi usa properties.keySet per scorrere le altre proprietà nell'oggetto TableEntity ed eseguirne il mapping all'oggetto WeatherDataModel, ad eccezione delle proprietà già mappate direttamente.

Modificare il codice nel metodo mapTableEntityToWeatherDataModel affinché corrisponda al blocco di codice seguente.

public static WeatherDataModel mapTableEntityToWeatherDataModel(TableEntity entity) {
    WeatherDataModel observation = new WeatherDataModel(
        entity.getPartitionKey(), entity.getRowKey(),
        entity.getTimestamp(), entity.getETag());
    rearrangeEntityProperties(observation.getPropertyMap(), entity.getProperties());
    return observation;
}

private static void rearrangeEntityProperties(Map<String, Object> target, Map<String, Object> source) {
    Constants.DEFAULT_LIST_OF_KEYS.forEach(key -> {
        if (source.containsKey(key)) {
            target.put(key, source.get(key));
        }
    });
    source.keySet().forEach(key -> {
        if (Constants.DEFAULT_LIST_OF_KEYS.parallelStream().noneMatch(defaultKey -> defaultKey.equals(key))
        && Constants.EXCLUDE_TABLE_ENTITY_KEYS.parallelStream().noneMatch(defaultKey -> defaultKey.equals(key))) {
            target.put(key, source.get(key));
        }
    });
}

Filtrare le righe restituite da una tabella

Per filtrare le righe restituite da una tabella, è possibile passare al metodo listEntities una stringa di filtro di stile OData. Ad esempio, se si desidera ottenere tutte le letture meteo per Chicago tra la mezzanotte del 1° luglio 2021 e la mezzanotte del 2 luglio 2021 (inclusi), passare la stringa di filtro seguente.

PartitionKey eq 'Chicago' and RowKey ge '2021-07-01 12:00 AM' and RowKey le '2021-07-02 12:00 AM'

È possibile visualizzare tutti gli operatori di filtro OData nel sito Web OData nella sezione Filtra opzione query di sistema.

Nell'applicazione di esempio l'oggetto FilterResultsInputModel è progettato per acquisire tutti i criteri di filtro forniti dall'utente.

public class FilterResultsInputModel implements Serializable {

    private String partitionKey;

    private String rowKeyDateStart;

    private String rowKeyTimeStart;

    private String rowKeyDateEnd;

    private String rowKeyTimeEnd;

    private Double minTemperature;

    private Double maxTemperature;

    private Double minPrecipitation;

    private Double maxPrecipitation;

    public String getPartitionKey() {
        return partitionKey;
    }

    public void setPartitionKey(String partitionKey) {
        this.partitionKey = partitionKey;
    }

    public String getRowKeyDateStart() {
        return rowKeyDateStart;
    }

    public void setRowKeyDateStart(String rowKeyDateStart) {
        this.rowKeyDateStart = rowKeyDateStart;
    }

    public String getRowKeyTimeStart() {
        return rowKeyTimeStart;
    }

    public void setRowKeyTimeStart(String rowKeyTimeStart) {
        this.rowKeyTimeStart = rowKeyTimeStart;
    }

    public String getRowKeyDateEnd() {
        return rowKeyDateEnd;
    }

    public void setRowKeyDateEnd(String rowKeyDateEnd) {
        this.rowKeyDateEnd = rowKeyDateEnd;
    }

    public String getRowKeyTimeEnd() {
        return rowKeyTimeEnd;
    }

    public void setRowKeyTimeEnd(String rowKeyTimeEnd) {
        this.rowKeyTimeEnd = rowKeyTimeEnd;
    }

    public Double getMinTemperature() {
        return minTemperature;
    }

    public void setMinTemperature(Double minTemperature) {
        this.minTemperature = minTemperature;
    }

    public Double getMaxTemperature() {
        return maxTemperature;
    }

    public void setMaxTemperature(Double maxTemperature) {
        this.maxTemperature = maxTemperature;
    }

    public Double getMinPrecipitation() {
        return minPrecipitation;
    }

    public void setMinPrecipitation(Double minPrecipitation) {
        this.minPrecipitation = minPrecipitation;
    }

    public Double getMaxPrecipitation() {
        return maxPrecipitation;
    }

    public void setMaxPrecipitation(Double maxPrecipitation) {
        this.maxPrecipitation = maxPrecipitation;
    }
}

Quando l'oggetto viene passato al metodo retrieveEntitiesByFilter nella classe TableServiceImpl, crea una stringa di filtro per ogni valore di proprietà non Null. Crea quindi una stringa di filtro combinata unendo tutti i valori insieme a una clausola “and". Questa stringa di filtro combinata viene passata al metodo listEntities sull'oggetto TableClient e verranno restituite solo le righe corrispondenti alla stringa di filtro. È possibile usare un metodo simile nel codice per costruire stringhe di filtro appropriate come richiesto dall'applicazione.

public List<WeatherDataModel> retrieveEntitiesByFilter(FilterResultsInputModel model) {

    List<String> filters = new ArrayList<>();

    if (!StringUtils.isEmptyOrWhitespace(model.getPartitionKey())) {
        filters.add(String.format("PartitionKey eq '%s'", model.getPartitionKey()));
    }
    if (!StringUtils.isEmptyOrWhitespace(model.getRowKeyDateStart())
            && !StringUtils.isEmptyOrWhitespace(model.getRowKeyTimeStart())) {
        filters.add(String.format("RowKey ge '%s %s'", model.getRowKeyDateStart(), model.getRowKeyTimeStart()));
    }
    if (!StringUtils.isEmptyOrWhitespace(model.getRowKeyDateEnd())
            && !StringUtils.isEmptyOrWhitespace(model.getRowKeyTimeEnd())) {
        filters.add(String.format("RowKey le '%s %s'", model.getRowKeyDateEnd(), model.getRowKeyTimeEnd()));
    }
    if (model.getMinTemperature() != null) {
        filters.add(String.format("Temperature ge %f", model.getMinTemperature()));
    }
    if (model.getMaxTemperature() != null) {
        filters.add(String.format("Temperature le %f", model.getMaxTemperature()));
    }
    if (model.getMinPrecipitation() != null) {
        filters.add(String.format("Precipitation ge %f", model.getMinPrecipitation()));
    }
    if (model.getMaxPrecipitation() != null) {
        filters.add(String.format("Precipitation le %f", model.getMaxPrecipitation()));
    }

    List<WeatherDataModel> modelList = tableClient.listEntities(new ListEntitiesOptions()
        .setFilter(String.join(" and ", filters)), null, null).stream()
        .map(WeatherDataUtils::mapTableEntityToWeatherDataModel)
        .collect(Collectors.toList());
    return Collections.unmodifiableList(WeatherDataUtils.filledValue(modelList));
}

Inserire dati usando un oggetto TableEntity

Il modo più semplice per aggiungere dati a una tabella consiste nell'usare un oggetto TableEntity. In questo esempio i dati vengono mappati da un oggetto modello di input a un oggetto TableEntity. Le proprietà dell'oggetto di input che rappresentano il nome della stazione meteo e la data/ora di osservazione vengono mappate, rispettivamente, alle proprietà PartitionKey e RowKey, che formano insieme una chiave univoca per la riga della tabella. Le proprietà aggiuntive sull'oggetto modello di input vengono quindi mappate alle proprietà del dizionario nell'oggetto TableClient. Infine, viene usato il metodo createEntity sull'oggetto TableClient per inserire dati nella tabella.

Modificare la classe insertEntity nell'applicazione di esempio in modo da contenere il codice seguente.

public void insertEntity(WeatherInputModel model) {
    tableClient.createEntity(WeatherDataUtils.createTableEntity(model));
}

Eseguire l'upsert dei dati tramite un oggetto TableEntity

Se si tenta di inserire una riga in una tabella con una combinazione "chiave di partizione/chiave di riga" già esistente nella tabella, si riceverà un errore. Per questo motivo, quando si aggiungono righe a una tabella è spesso preferibile usare il metodo upsertEntity anziché insertEntity. Se la combinazione "chiave di partizione/chiave di riga" specificata esiste già nella tabella, il metodo upsertEntity aggiornerà la riga esistente. In caso contrario, la riga viene aggiunta alla tabella.

public void upsertEntity(WeatherInputModel model) {
    tableClient.upsertEntity(WeatherDataUtils.createTableEntity(model));
}

Inserire o eseguire l'upsert dei dati con proprietà variabili

Uno dei vantaggi di cui è possibile usufruire usando l'API Table di Azure Cosmos DB è che, se un oggetto caricato in una tabella contiene nuove proprietà, queste vengono aggiunte automaticamente alla tabella e i valori vengono archiviati in Azure Cosmos DB. Non è necessario eseguire istruzioni DDL come ALTER TABLE per aggiungere colonne, come in un database tradizionale.

Questo modello offre flessibilità all'applicazione quando si gestiscono origini dati che possono aggiungere o modificare i dati da acquisire nel tempo o quando input diversi forniscono dati diversi all'applicazione. Nell'applicazione di esempio è possibile simulare una stazione meteo che invia non solo i dati meteo di base, ma anche alcuni valori aggiuntivi. Quando un oggetto con queste nuove proprietà viene archiviato nella tabella per la prima volta, le proprietà corrispondenti (colonne) verranno aggiunte automaticamente alla tabella.

Nell'applicazione di esempio la classe ExpandableWeatherObject viene compilata sulla base di un dizionario interno per supportare qualsiasi set di proprietà dell'oggetto. Questa classe rappresenta un modello tipico per i casi in cui un oggetto deve contenere un set arbitrario di proprietà.

public class ExpandableWeatherObject {

    private String stationName;

    private String observationDate;

    private Map<String, Object> propertyMap = new HashMap<String, Object>();

    public String getStationName() {
        return stationName;
    }

    public void setStationName(String stationName) {
        this.stationName = stationName;
    }

    public String getObservationDate() {
        return observationDate;
    }

    public void setObservationDate(String observationDate) {
        this.observationDate = observationDate;
    }

    public Map<String, Object> getPropertyMap() {
        return propertyMap;
    }

    public void setPropertyMap(Map<String, Object> propertyMap) {
        this.propertyMap = propertyMap;
    }

    public boolean containsProperty(String key) {
        return this.propertyMap.containsKey(key);
    }

    public Object getPropertyValue(String key) {
        return containsProperty(key) ? this.propertyMap.get(key) : null;
    }

    public void putProperty(String key, Object value) {
        this.propertyMap.put(key, value);
    }

    public List<String> getPropertyKeys() {
        List<String> list = Collections.synchronizedList(new ArrayList<String>());
        Iterator<String> iterators = this.propertyMap.keySet().iterator();
        while (iterators.hasNext()) {
            list.add(iterators.next());
        }
        return Collections.unmodifiableList(list);
    }

    public Integer getPropertyCount() {
        return this.propertyMap.size();
    }
}

Per inserire o eseguire l'upsert di un oggetto di questo tipo usando l'API per Table, eseguire il mapping delle proprietà dell'oggetto espandibile in un oggetto TableEntity e usare il metodo createEntity o upsertEntity sull'oggetto TableClient, in base alle esigenze.

public void insertExpandableEntity(ExpandableWeatherObject model) {
    tableClient.createEntity(WeatherDataUtils.createTableEntity(model));
}

public void upsertExpandableEntity(ExpandableWeatherObject model) {
    tableClient.upsertEntity(WeatherDataUtils.createTableEntity(model));
}

Aggiornare un'entità

Le entità possono essere aggiornate chiamando il metodo updateEntity sull'oggetto TableClient. Poiché un'entità (riga) archiviata usando l'API Table potrebbe contenere qualsiasi set arbitrario di proprietà, è spesso utile creare un oggetto di aggiornamento basato su un oggetto dizionario simile all'oggetto ExpandableWeatherObject descritto in precedenza. In questo caso, l'unica differenza risiede nell'aggiunta di una proprietà etag per il controllo della concorrenza durante gli aggiornamenti.

public class UpdateWeatherObject {

    private String stationName;

    private String observationDate;

    private String etag;

    private Map<String, Object> propertyMap = new HashMap<String, Object>();

    public String getStationName() {
        return stationName;
    }

    public void setStationName(String stationName) {
        this.stationName = stationName;
    }

    public String getObservationDate() {
        return observationDate;
    }

    public void setObservationDate(String observationDate) {
        this.observationDate = observationDate;
    }

    public String getEtag() {
        return etag;
    }

    public void setEtag(String etag) {
        this.etag = etag;
    }

    public Map<String, Object> getPropertyMap() {
        return propertyMap;
    }

    public void setPropertyMap(Map<String, Object> propertyMap) {
        this.propertyMap = propertyMap;
    }
}

Nell'app di esempio, questo oggetto viene passato al metodo updateEntity nella classe TableServiceImpl. Questo metodo carica prima l'entità esistente dall'API Table usando il metodo getEntity su TableClient e quindi aggiorna l'oggetto entità e usa il metodo updateEntity per salvare gli aggiornamenti nel database. Il metodo updateEntity accetta l'Etag corrente dell'oggetto per assicurarsi che l'oggetto non sia stato modificato dopo il caricamento iniziale. Se si vuole aggiornare l'entità indipendentemente da questo, è possibile passare un valore di etag al metodo updateEntity.

public void updateEntity(UpdateWeatherObject model) {
    TableEntity tableEntity = tableClient.getEntity(model.getStationName(), model.getObservationDate());
    Map<String, Object> propertiesMap = model.getPropertyMap();
    propertiesMap.keySet().forEach(key -> tableEntity.getProperties().put(key, propertiesMap.get(key)));
    tableClient.updateEntity(tableEntity);
}

Rimuovere un'entità

Per rimuovere un'entità da una tabella, chiamare il metodo deleteEntity sull'oggetto TableClient con la chiave di partizione e la chiave di riga dell'oggetto.

public void deleteEntity(WeatherInputModel model) {
    tableClient.deleteEntity(model.getStationName(),
            WeatherDataUtils.formatRowKey(model.getObservationDate(), model.getObservationTime()));
}

7 - Eseguire il codice

Eseguire l'applicazione di esempio per interagire con l'API Table di Azure Cosmos DB. La prima volta che si esegue l'applicazione, non saranno presenti dati perché la tabella è vuota. Usare uno qualsiasi dei pulsanti nella parte superiore dell'applicazione per aggiungere dati alla tabella.

A screenshot of the application showing the location of the buttons used to insert data into Azure Cosmos DB using the Table API.

Selezionando il pulsante Inserisci tramite Table Entity, si apre una finestra di dialogo che consente di inserire o eseguire l'upsert di una nuova riga utilizzando un oggetto TableEntity.

A screenshot of the application showing the dialog box used to insert data using a TableEntity object.

Se si seleziona il pulsante Inserisci tramite dati espandibili, viene visualizzata una finestra di dialogo che consente di inserire un oggetto con proprietà personalizzate, dimostrando come l'API Table di Azure Cosmos DB aggiunga automaticamente proprietà (colonne) alla tabella quando necessario. Usare il pulsante Aggiungi campo personalizzato per aggiungere una o più nuove proprietà e dimostrare questa funzionalità.

A screenshot of the application showing the dialog box used to insert data using an object with custom fields.

Usare il pulsante Inserisci dati di esempio per caricare alcuni dati di esempio nella tabella di Azure Cosmos DB.

A screenshot of the application showing the location of the sample data insert button.

Selezionare la voce Filtra i risultati nel menu in alto per aprire la pagina Filtra i risultati. In questa pagina compilare i criteri di filtro per illustrare come creare e passare una clausola di filtro all'API Table di Azure Cosmos DB.

A screenshot of the application showing filter results page and highlighting the menu item used to navigate to the page.

Pulire le risorse

Dopo aver finito di usare l'applicazione di esempio, è necessario rimuovere tutte le risorse di Azure correlate a questo articolo dall'account Azure. A questo scopo, eliminare il gruppo di risorse.

È possibile eliminare un gruppo di risorse usando il portale di Azure e seguendo questa procedura.

Istruzioni Schermata
Per accedere al gruppo di risorse, nella barra di ricerca digitare il nome del gruppo di risorse. Quindi nella scheda Gruppi di risorse selezionare il nome del gruppo di risorse. A screenshot showing how to search for a resource group.
Selezionare Elimina gruppo di risorse dalla barra degli strumenti nella parte superiore della pagina del gruppo di risorse. A screenshot showing the location of the Delete resource group button.
Nella parte destra della schermata verrà visualizzata una finestra di dialogo in cui viene chiesto di confermare l'eliminazione del gruppo di risorse.
  1. Digitare il nome completo del gruppo di risorse nella casella di testo per confermare l'eliminazione come indicato.
  2. Selezionare il pulsante Elimina in fondo alla pagina.
A screenshot showing the confirmation dialog for deleting a resource group.

Passaggi successivi

In questa guida di avvio rapido si è appreso come creare un account Azure Cosmos DB, come creare una tabella con Esplora dati e come eseguire un'app. È ora possibile eseguire query sui dati usando l'API per Table.