Inicio rápido: Creación de una aplicación de API for Table con el SDK de Java y Azure Cosmos DB

SE APLICA A: Table

En este inicio rápido se muestra cómo acceder a Table API de Azure Cosmos DB desde una aplicación de Java. API for Table de Azure Cosmos DB es un almacén de datos sin esquema que permite a las aplicaciones almacenar datos NoSQL estructurados en la nube. Dado que los datos se almacenan en un diseño sin esquema, las nuevas propiedades (columnas) se agregan automáticamente a la tabla cuando se agrega un objeto con un nuevo atributo a la tabla.

Las aplicaciones de Java pueden acceder a API for Table de Azure Cosmos DB usando la biblioteca cliente azure-data-tables.

Requisitos previos

La aplicación de ejemplo está escrita en Spring Boot 2.6.4. Puede usar Visual Studio Code o IntelliJ IDEA como IDE.

Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.

Aplicación de ejemplo

La aplicación de ejemplo de este tutorial se puede clonar o descargar desde el repositorio https://github.com/Azure-Samples/msdocs-azure-data-tables-sdk-java. En el repositorio de ejemplo se incluyen tanto una aplicación de inicio como una completa.

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

La aplicación de ejemplo usa datos meteorológicos como ejemplo para demostrar las funcionalidades de Table API. Los objetos que representan observaciones meteorológicas se almacenan y recuperan mediante API for Table, incluido el almacenamiento de objetos con propiedades adicionales para mostrar la funcionalidad sin esquema de API for Table.

Captura de pantalla de la aplicación finalizada que muestra los datos almacenados en una tabla de Azure Cosmos DB con API for Table.

1 - Creación de una cuenta de Azure Cosmos DB

En primer lugar, debe crear una cuenta de API for Table de Azure Cosmos DB que contendrá las tablas usadas en la aplicación. Esto se puede realizar mediante Azure Portal, la CLI de Azure o Azure PowerShell.

Inicie sesión en Azure Portal y siga estos pasos para crear una cuenta de Azure Cosmos DB.

Instrucciones Instantánea
En Azure Portal:
  1. En la barra de búsqueda de la parte superior de Azure Portal, escriba "Azure cosmos DB".
  2. En el menú que aparece debajo de la barra de búsqueda, en la opción Servicios, seleccione el elemento etiquetado como Azure Cosmos DB.
Captura de pantalla que muestra cómo usar el cuadro de búsqueda de la barra de herramientas superior para buscar cuentas de Azure Cosmos DB en Azure.
En la página Azure Cosmos DB, seleccione +Crear. Captura de pantalla que muestra la ubicación del botón Crear en la página de cuentas de Azure Cosmos DB en Azure.
En la página Selección de la opción de API, elija la opción Tabla de Azure. Captura de pantalla que muestra la opción Tabla de Azure como opción correcta para seleccionar.
En la página Creación de una cuenta de Azure Cosmos DB: Tabla de Azure, rellene el formulario de la siguiente manera.
  1. Cree un nuevo grupo de recursos para la cuenta de almacenamiento denominado rg-msdocs-tables-sdk-demo seleccionando el vínculo Crear nuevo en Grupo de recursos.
  2. Asigne a su cuenta de almacenamiento un nombre de cosmos-msdocs-tables-sdk-demo-XYZ, donde XYZ son tres caracteres aleatorios para crear un nombre de cuenta único. Los nombres de cuenta de Azure Cosmos DB deben tener entre 3 y 44 caracteres y solo pueden contener letras minúsculas, números o el carácter de guion (-).
  3. Seleccione la región para la cuenta de almacenamiento.
  4. Seleccione el rendimiento Estándar.
  5. Seleccione Rendimiento aprovisionado para este ejemplo en Modo de capacidad.
  6. Seleccione Aplicar en Aplicar descuento del nivel Gratis para este ejemplo.
  7. Seleccione el botón Revisar y crear en la parte inferior de la pantalla y, a continuación, seleccione "Crear" en la pantalla de resumen para crear su cuenta de Azure Cosmos DB. Este proceso puede tardar varios minutos.
Captura de pantalla que muestra cómo rellenar los campos de la página de creación de la cuenta de Azure Cosmos DB.

2 - Creación de una tabla

Después, debe crear una tabla dentro de la cuenta de Azure Cosmos DB que es la que usará la aplicación. A diferencia de una base de datos tradicional, solo es necesario especificar el nombre de la tabla, no las propiedades (columnas) de la tabla. A medida que se cargan datos en la tabla, las propiedades (columnas) se crean automáticamente según sea necesario.

En Azure Portal, complete los pasos siguientes para crear una tabla dentro de la cuenta de Azure Cosmos DB.

Instrucciones Instantánea
En Azure Portal, vaya a la página de información general de la cuenta de Azure Cosmos DB. Para ir a la página de información general de la cuenta de Azure Cosmos DB, escriba el nombre (cosmos-msdocs-tables-sdk-demo-XYZ) de la cuenta de Azure Cosmos DB en la barra de búsqueda superior y busque en el encabezado de recursos. Seleccione el nombre de la cuenta de Azure Cosmos DB para ir a la página de información general. Captura de pantalla que muestra cómo usar el cuadro de búsqueda de la barra de herramientas superior para encontrar la cuenta de Azure Cosmos DB.
En la página de información general, seleccione +Agregar tabla. El cuadro de diálogo Nueva tabla se deslizará desde el lado derecho de la página. Captura de pantalla que muestra la ubicación del botón Agregar tabla.
En el cuadro de diálogo Nueva tabla, complete el formulario de la siguiente manera.
  1. Escriba el nombre WeatherData para el id. de tabla. Recuerde que este es el nombre de la tabla.
  2. Seleccione Manual en Rendimiento de la tabla (escala automática) para este ejemplo.
  3. Use el valor predeterminado de 400 en las RU/s estimadas.
  4. Haga clic en el botón Aceptar para crear la tabla.
Captura de pantalla que muestra cómo usar el cuadro de diálogo Nueva tabla para una tabla de Azure Cosmos DB.

3 - Obtención de la cadena de conexión de Azure Cosmos DB

Para acceder a las tablas de Azure Cosmos DB, la aplicación necesita la cadena de conexión de la tabla para la cuenta de almacenamiento de CosmosDB. La cadena de conexión se puede recuperar mediante Azure Portal, la CLI de Azure o Azure PowerShell.

Instrucciones Instantánea
En el lado izquierdo de la página de la cuenta de Azure Cosmos DB, busque el elemento de menú denominado Cadena de conexión en el encabezado Configuración y selecciónelo. Se le llevará a una página donde puede recuperar la cadena de conexión de la cuenta de almacenamiento. Captura de pantalla que muestra la ubicación del vínculo de las cadenas de conexión en la página de Azure Cosmos DB.
Copie el valor CADENA DE CONEXIÓN PRINCIPAL para usarlo en la aplicación. Captura de pantalla que muestra la cadena de conexión que se va a seleccionar y usar en la aplicación.

La cadena de conexión de la cuenta de Azure Cosmos DB se considera un secreto de aplicación y se debe proteger como cualquier otro secreto o contraseña de aplicación. En este ejemplo, se usa POM para almacenar la cadena de conexión durante el desarrollo y hacer que esté disponible para la aplicación.

<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- Inclusión del paquete azure-data-tables

Para acceder a API for Table de Azure Cosmos DB desde una aplicación de Java, incluya el paquete azure-data-tables.

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

5 - Configuración del cliente de Table API en TableServiceConfig.java

Azure SDK se comunica con Azure mediante objetos de cliente para ejecutar diferentes operaciones en Azure. El objeto TableClient es el objeto que se usa para comunicarse con API for Table de Azure Cosmos DB.

Normalmente, una aplicación creará un único objeto TableClient por cada tabla que se usará en toda la aplicación. Se recomienda indicar que un método genera un bean de objeto TableClient que va a administrar el contenedor de Spring y una base de datos única para lograrlo.

En el archivo TableServiceConfig.java de la aplicación, edite el método tableClientConfiguration() para que coincida con el siguiente fragmento de código:

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

También tiene que agregar la siguiente instrucción using en la parte superior del archivo TableServiceConfig.java.

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

6 - Implementación de las operaciones de tabla de Azure Cosmos DB

Todas las operaciones de tablas de Azure Cosmos DB de la aplicación de ejemplo se implementan en la clase TablesServiceImpl ubicada en el directorio Services. Deberá importar el paquete del SDK de 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;

Al principio de la clase TableServiceImpl, agregue una variable de miembro para el objeto TableClient y un constructor para permitir que el objeto TableClient se inyecte en la clase.

@Autowired
private TableClient tableClient;

Obtención de filas de una tabla

La clase TableClient contiene un método llamado listEntities que permite seleccionar filas de la tabla. En este ejemplo, dado que no se pasan parámetros al método, se seleccionarán todas las filas de la tabla.

El método también toma un parámetro genérico de tipo TableEntity que especifica cómo se devolverán los datos de la clase del modelo. En este caso, se usa la clase integrada TableEntity, lo que significa que el método listEntities devolverá una colección PagedIterable<TableEntity> como resultado.

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

La clase TableEntity definida en el paquete com.azure.data.tables.models tiene propiedades para los valores de clave de partición y clave de fila de la tabla. Juntos, estos dos valores forman una clave única para la fila de la tabla. En esta aplicación de ejemplo, el nombre de la estación meteorológica (ciudad) se almacena en la clave de partición y la fecha y hora de la observación se almacenan en la clave de fila. Todas las demás propiedades (temperatura, humedad, velocidad del viento) se almacenan en un diccionario en el objeto TableEntity.

Es habitual asignar un objeto TableEntity a un objeto de su propia definición. La aplicación de ejemplo define la clase WeatherDataModel en el directorio Models para este propósito. Esta clase tiene propiedades para el nombre de la estación y la fecha de observación a las que se asignarán la clave de partición y la clave de fila, lo que proporciona nombres de propiedad más significativos para estos valores. A continuación, usa un diccionario para almacenar todas las demás propiedades en el objeto. Se trata de un patrón común al trabajar con el almacenamiento de tablas, ya que una fila puede tener un número arbitrario de propiedades y queremos que nuestros objetos del modelo puedan capturar todas ellas. Esta clase también contiene métodos para enumerar las propiedades de la clase.

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

El método mapTableEntityToWeatherDataModel se usa para asignar un objeto TableEntity a un objeto WeatherDataModel. El método mapTableEntityToWeatherDataModel asigna directamente las propiedades PartitionKey, RowKey, Timestamp y Etag y, a continuación, usa la propiedad properties.keySet para recorrer en iteración las demás propiedades del objeto TableEntity y asignar esas propiedades al objeto WeatherDataModel, menos las propiedades que ya se han asignado directamente.

Edite el código del método mapTableEntityToWeatherDataModel para que coincida con el siguiente bloque de código.

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

Filtrado de las filas devueltas de una tabla

Para filtrar las filas devueltas de una tabla, puede pasar una cadena de filtro de estilo OData al método listEntities. Por ejemplo, si quisiera obtener todas las lecturas meteorológicas de Chicago entre la medianoche del 1 de julio de 2021 y la medianoche del 2 de julio de 2021 (ambos incluidos), pasaría la siguiente cadena de filtro.

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

Puede ver todos los operadores de filtrado de OData en el sitio web de OData, en la sección Opción de consulta del sistema de filtrado.

En la aplicación de ejemplo, el objeto FilterResultsInputModel está diseñado para capturar los criterios de filtrado proporcionados por el usuario.

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

Cuando se pasa este objeto al método retrieveEntitiesByFilter de la clase TableServiceImpl, crea una cadena de filtrado para cada valor de propiedad que no sea NULL. A continuación, crea una cadena de filtrado combinada combinando todos los valores con una cláusula "and". Esta cadena de filtrado combinada se pasa al método listEntities en el objeto TableClient y solo se devolverán las filas que coincidan con la cadena de filtrado. Puede usar un método similar en el código para construir cadenas de filtrado adecuadas según sea necesario para la aplicación.

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

Inserción de datos mediante un objeto TableEntity

La manera más sencilla de agregar datos a una tabla es mediante el uso de un objeto TableEntity. En este ejemplo, los datos se asignan desde un objeto del modelo de entrada a un objeto TableEntity. Las propiedades del objeto de entrada que representan el nombre de la estación meteorológica y la fecha y hora de observación se asignan a las propiedades PartitionKey y RowKey respectivamente, que juntas forman una clave única para la fila de la tabla. A continuación, las propiedades adicionales del objeto del modelo de entrada se asignan a las propiedades del diccionario en el objeto TableClient. Por último, se usa el método createEntity del objeto TableClient para insertar los datos en la tabla.

Modifique la clase insertEntity de la aplicación de ejemplo para que contenga el código siguiente.

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

Actualizar/insertar (upsert) datos mediante un objeto TableEntity

Si intenta insertar una fila en una tabla con una combinación de clave de partición y clave de fila que ya existe en esa tabla, recibirá un error. Por este motivo, a menudo es preferible usar upsertEntity en lugar del método insertEntity al agregar filas a una tabla. Si la combinación de clave de partición y clave de fila especificada ya existe en la tabla, el método upsertEntity actualizará la fila existente. De lo contrario, se agregará la fila a la tabla.

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

Insertar o actualizar/insertar (upsert) datos con propiedades variables

Una de las ventajas de usar API for Table de Azure Cosmos DB es que, si un objeto que se carga en una tabla contiene nuevas propiedades, esas propiedades se agregan automáticamente a la tabla y los valores se almacenan en Azure Cosmos DB. No es necesario ejecutar instrucciones DDL como ALTER TABLE para agregar columnas como en una base de datos tradicional.

Este modelo proporciona flexibilidad a la aplicación cuando se trabaja con orígenes de datos que pueden agregar o modificar qué datos se deben capturar a lo largo del tiempo o cuando distintas entradas proporcionan datos diferentes a la aplicación. En la aplicación de ejemplo, podemos simular una estación meteorológica que envía no solo los datos meteorológicos básicos, sino también algunos valores adicionales. Cuando un objeto con estas nuevas propiedades se almacena en la tabla por primera vez, las propiedades correspondientes (columnas) se agregarán automáticamente a la tabla.

En la aplicación de ejemplo, la clase ExpandableWeatherObject se basa en un diccionario interno para admitir cualquier conjunto de propiedades en el objeto. Esta clase representa un patrón típico para los casos en los que un objeto debe contener un conjunto arbitrario de propiedades.

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

Para insertar o actualizar/insertar (upsert) este tipo de objeto con API for Table, asigne las propiedades del objeto ampliable a un objeto TableEntity y use los métodos createEntity o upsertEntity en el objeto TableClient según corresponda.

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

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

Actualización de una entidad

Las entidades se pueden actualizar llamando al método updateEntity en el objeto TableClient. Dado que una entidad (fila) almacenada mediante Table API podría contener cualquier conjunto arbitrario de propiedades, a menudo resulta útil crear un objeto de actualización basado en un objeto de diccionario similar al objeto ExpandableWeatherObject mencionado anteriormente. En este caso, la única diferencia es la adición de la propiedad etag, que se usa para el control de la simultaneidad durante las actualizaciones.

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

En la aplicación de ejemplo, este objeto se pasa al método updateEntity de la clase TableServiceImpl. Este método carga primero la entidad existente de Table API mediante el método getEntity de TableClient. A continuación, actualiza ese objeto de entidad y usa el método updateEntity para guardar las actualizaciones en la base de datos. Observe cómo el método updateEntity toma la etiqueta ETag actual del objeto para garantizar que el objeto no haya cambiado desde que se cargó inicialmente. Si desea actualizar la entidad independientemente, puede pasar un valor de etag al método 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);
}

Eliminación de una entidad

Para quitar una entidad de una tabla, llame al método deleteEntity del objeto TableClient con la clave de partición y la clave de fila del objeto.

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

7 - Ejecución del código

Ejecute la aplicación de ejemplo para interactuar con API for Table de Azure Cosmos DB. La primera vez que ejecute la aplicación, no habrá datos porque la tabla está vacía. Use cualquiera de los botones de la parte superior de la aplicación para agregar datos a la tabla.

Captura de pantalla de la aplicación que muestra la ubicación de los botones usados para insertar datos en Azure Cosmos DB con API for Table.

Al seleccionar el botón Insert using Table Entity (Insertar mediante TableEntity), se abre un cuadro de diálogo que le permite insertar o actualizar/insertar (upsert) una fila nueva mediante un objeto TableEntity.

Captura de pantalla de la aplicación que muestra el cuadro de diálogo utilizado para insertar datos mediante un objeto TableEntity.

Al seleccionar el botón Insertar mediante datos ampliables, se abre un cuadro de diálogo que permite insertar un objeto con propiedades personalizadas, lo que muestra cómo API for Table de Azure Cosmos DB agrega automáticamente propiedades (columnas) a la tabla cuando es necesario. Use el botón Add Custom Field (Agregar campo personalizado) para agregar una o varias propiedades nuevas y demostrar esta funcionalidad.

Captura de pantalla de la aplicación que muestra el cuadro de diálogo usado para insertar datos mediante un objeto con campos personalizados.

Use el botón Insertar datos de ejemplo para cargar algunos datos de ejemplo en la tabla de Azure Cosmos DB.

Captura de pantalla de la aplicación que muestra la ubicación del botón para insertar datos de ejemplo.

Seleccione el elemento Filter Results (Filtrar resultados) en el menú superior para ir a la página Filter Results (Filtrar resultados). En esta página, rellene los criterios de filtro para mostrar cómo se puede crear y pasar una cláusula de filtro a API for Table de Azure Cosmos DB.

Captura de pantalla de la aplicación que muestra la página Filtrar resultados y resalta el elemento de menú que se usa para ir a la página.

Limpieza de recursos

Cuando haya terminado con la aplicación de ejemplo, debe quitar todos los recursos de Azure relacionados con este artículo de la cuenta de Azure. Para ello, elimine el grupo de recursos.

Se puede eliminar un grupo de recursos mediante Azure Portal haciendo lo siguiente.

Instrucciones Instantánea
Para ir al grupo de recursos, en la barra de búsqueda, escriba el nombre del grupo de recursos. A continuación, en la pestaña Grupos de recursos, seleccione el nombre del grupo de recursos. Captura de pantalla que muestra cómo buscar un grupo de recursos.
Seleccione Eliminar grupo de recursos en la barra de herramientas de la parte superior de la página del grupo de recursos. Captura de pantalla que muestra la ubicación del botón Eliminar grupo de recursos.
Aparecerá un cuadro de diálogo a la derecha de la pantalla en el que se le pedirá que confirme la eliminación del grupo de recursos.
  1. Escriba el nombre del grupo de recursos en el cuadro de texto para confirmar la eliminación, tal como se indica.
  2. Seleccione el botón Eliminar en la parte inferior de la página.
Captura de pantalla que muestra el cuadro de diálogo de confirmación para eliminar un grupo de recursos.

Pasos siguientes

En esta guía de inicio rápido, ha obtenido información sobre cómo crear una cuenta de Azure Cosmos DB, crear una tabla mediante el Explorador de datos y ejecutar una aplicación. Ahora ya puede consultar los datos mediante la API para Table.