Schnellstart: Erstellen einer API für Table-App mit Java SDK und Azure Cosmos DB

GILT FÜR: Tabelle

Dieser Schnellstart zeigt, wie Sie aus einer Java-Anwendung auf die Tabellen-API von Azure Cosmos DB zugreifen können. Die Tabellen-API von Azure Cosmos DB ist ein schemaloser Datenspeicher, der es Anwendungen ermöglicht, strukturierte NoSQL-Daten in der Cloud zu speichern. Da Daten in einem schemalosen Entwurf gespeichert werden, werden der Tabelle automatisch neue Eigenschaften (Spalten) hinzugefügt, wenn der Tabelle ein Objekt mit einem neuen Attribut hinzugefügt wird.

Java-Anwendungen können auf die Tabellen-API von Azure Cosmos DB mit der azure-data-tables-Clientbibliothek zugreifen.

Voraussetzungen

Die Beispielanwendung wurde in Spring Boot 2.6.4 geschrieben. Sie können entweder Visual Studio Code oder IntelliJ IDEA als IDE verwenden.

Wenn Sie kein Azure-Abonnement besitzen, erstellen Sie ein kostenloses Konto, bevor Sie beginnen.

Beispielanwendung

Die Beispielanwendung für dieses Tutorial kann aus dem Repository https://github.com/Azure-Samples/msdocs-azure-data-tables-sdk-java geklont oder heruntergeladen werden. Sowohl eine Starter- als auch eine vollständige App sind im Beispielrepository enthalten.

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

Die Beispielanwendung verwendet Wetterdaten als Beispiel, um die Funktionen der Tabellen-API zu zeigen. Objekte, die Wetterbeobachtungen darstellen, werden mithilfe der API für Table gespeichert und abgerufen, einschließlich der Speicherung von Objekten mit zusätzlichen Eigenschaften, um die schemalosen Funktionen der Tabellen-API zu zeigen.

Screenshot der fertiggestellten Anwendung mit Daten, die in einer Azure Cosmos DB-Tabelle mit der Tabellen-API gespeichert werden.

1\. Erstellen eines Azure Cosmos DB-Kontos

Zunächst müssen Sie ein Azure Cosmos DB-Tabellen-API-Konto erstellen, das die in Ihrer Anwendung verwendeten Tabellen enthält. Hierfür können Sie das Azure-Portal, die Azure CLI oder Azure PowerShell verwenden.

Melden Sie sich beim Azure-Portal an, und führen Sie die folgenden Schritte aus, um ein Azure Cosmos DB-Konto zu erstellen.

Anweisungen Screenshot
Führen Sie im Azure-Portal die folgenden Schritte aus:
  1. Geben Sie oben im Azure-Portal auf der Suchleiste den Suchbegriff „Azure Cosmos DB“ ein.
  2. Wählen Sie im Menü, das unterhalb der Suchleiste angezeigt wird, unter Dienste das Element mit der Bezeichnung Azure Cosmos DB aus.
Screenshot: Verwenden des Suchfelds in der oberen Symbolleiste, um nach Azure Cosmos DB-Konten in Azure zu suchen
Wählen Sie auf der Seite Azure Cosmos DB die Option +Erstellen aus. Screenshot: Position der Schaltfläche „Erstellen“ auf der Seite „Azure Cosmos DB-Konten“ in Azure
Wählen Sie auf der Seite API-Option auswählen die Option Azure Table aus. Screenshot: Option „Azure-Tabelle“ als richtige auszuwählende Option.
Füllen Sie auf der Seite Azure Cosmos DB-Konto erstellen – Azure Table das Formular wie folgt aus.
  1. Erstellen Sie eine neue Ressourcengruppe für das Speicherkonto namens rg-msdocs-tables-sdk-demo, indem Sie unter Ressourcengruppe den Link Neu erstellen auswählen.
  2. Weisen Sie Ihrem Speicherkonto den Namen cosmos-msdocs-tables-sdk-demo-XYZ zu, wobei „XYZ“ drei beliebige zufällige Zeichen für die Bildung eines eindeutigen Kontonamens darstellen. Azure Cosmos DB-Kontonamen müssen zwischen 3 und 44 Zeichen lang sein und dürfen nur Kleinbuchstaben, Zahlen oder das Bindestrichzeichen (-) enthalten.
  3. Wählen Sie die Region für Ihr Speicherkonto aus.
  4. Wählen Sie für die Leistung die Option Standard aus.
  5. Wählen Sie für dieses Beispiel unter Kapazitätsmodus die Option Bereitgestellter Durchsatz aus.
  6. Wählen Sie für dieses Beispiel unter Tarifspezifischen Rabatt für den Free-Tarif anwenden die Option Anwenden aus.
  7. Wählen Sie am unteren Bildschirmrand die Schaltfläche Überprüfen und erstellen aus, und wählen Sie dann auf dem Bildschirm mit der Zusammenfassung die Option „Erstellen“ aus, um Ihr Azure Cosmos DB-Konto zu erstellen. Dieser Vorgang kann mehrere Minuten dauern.
Screenshot des Ausfüllens der Felder auf der Seite zum Erstellen von Azure Cosmos DB-Konten.

2\. Erstellen einer Tabelle

Nun müssen Sie eine Tabelle in Ihrem Azure Cosmos DB-Konto erstellen, das von Ihrer Anwendung verwendet wird. Im Gegensatz zu einer herkömmlichen Datenbank müssen Sie nur den Namen der Tabelle angeben, nicht die Eigenschaften (Spalten) in der Tabelle. Wenn Daten in die Tabelle geladen werden, werden die Eigenschaften (Spalten) bei Bedarf automatisch erstellt.

Führen Sie im Azure-Portal die folgenden Schritte aus, um eine Tabelle in Ihrem Azure Cosmos DB-Konto zu erstellen.

Anweisungen Screenshot
Navigieren Sie im Azure-Portal zur Übersichtsseite für das Azure Cosmos DB-Konto. Sie können zur Übersichtsseite für Ihr Azure Cosmos DB-Konto navigieren, indem Sie den Namen („cosmos-msdocs-tables-sdk-demo-XYZ“) Ihres Azure Cosmos DB-Kontos in die obere Suchleiste eingeben und unter der Überschrift „Ressourcen“ nachsehen. Wählen Sie den Namen Ihres Azure Cosmos DB-Kontos aus, um zur Übersichtsseite zu wechseln. Screenshot: Verwenden des Suchfelds in der oberen Symbolleiste, um nach Ihrem Azure Cosmos DB-Konten zu suchen
Wählen Sie auf der Seite „Übersicht“ die Option +Tabelle hinzufügen aus. Das Dialogfeld „Neue Tabelle“ wird rechts auf der Seite eingeblendet. Screenshot: Position der Schaltfläche „Tabelle hinzufügen“.
Füllen Sie im Dialogfeld Neue Tabelle das Formular wie folgt aus:
  1. Geben Sie den Namen WeatherData für die Tabellen-ID ein. Dies ist der Name der Tabelle.
  2. Wählen Sie für dieses Beispiel unter Table throughput (autoscale) (Tabellendurchsatz (Autoskalierung)) die Option Manuell aus.
  3. Verwenden Sie für Ihre geschätzten RU/s den Standardwert 400.
  4. Wählen Sie OK aus, um die Tabelle zu erstellen.
Screenshot des Dialogfelds „Neue Tabelle“ für eine Azure Cosmos DB-Tabelle.

3. Abrufen der Azure Cosmos DB-Verbindungszeichenfolge

Für den Zugriff auf Ihre Tabellen in Azure Cosmos DB benötigt Ihre App die Tabellenverbindungszeichenfolge für das CosmosDB-Speicherkonto. Die Verbindungszeichenfolge kann mithilfe des Azure-Portals, der Azure CLI oder mit Azure PowerShell abgerufen werden.

Anweisungen Screenshot
Suchen Sie links auf der Seite des Azure Cosmos DB-Kontos unter Einstellungen das Menüelement Verbindungszeichenfolge, und wählen Sie es aus. Sie gelangen zu einer Seite, auf der Sie die Verbindungszeichenfolge für das Speicherkonto abrufen können. Screenshot der Position des Links „Verbindungszeichenfolgen“ auf der Azure Cosmos DB-Seite.
Kopieren Sie den Wert der PRIMÄREN VERBINDUNGSZEICHENFOLGE zur Verwendung in Ihrer Anwendung. Screenshot: In Ihrer Anwendung auszuwählende und zu verwendende Verbindungszeichenfolge.

Die Verbindungszeichenfolge für Ihr Azure Cosmos DB-Konto gilt als App-Geheimnis und muss wie jedes andere App-Geheimnis oder Kennwort geschützt werden. In diesem Beispiel wird POM verwendet, um die Verbindungszeichenfolge während der Entwicklung zu speichern und für die Anwendung verfügbar zu machen.

<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\. Einschließen des Pakets „azure-data-tables“

Damit Sie aus einer Java-Anwendung auf die Tabellen-API von Azure Cosmos DB zugreifen können, schließen Sie das Paket azure-data-tables ein.

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

5\. Konfigurieren des Tabellenclients in „TableServiceConfig.java“

Das Azure SDK kommuniziert mit Azure mithilfe von Clientobjekten, um verschiedene Vorgänge in Azure auszuführen. Das TableClient-Objekt ist das Objekt, das für die Kommunikation mit der Tabellen-API von Azure Cosmos DB verwendet wird.

Eine Anwendung erstellt in der Regel ein einzelnes TableClient-Objekt pro Tabelle, das in der gesamten Anwendung verwendet wird. Es empfiehlt sich anzugeben, dass eine Methode ein TableClient-Objektbean erzeugt, das vom Spring-Container verwaltet wird, und zwar als Singleton, um dies zu erreichen.

Bearbeiten Sie in der Datei TableServiceConfig.java der Anwendung die tableClientConfiguration()-Methode so, dass sie dem folgenden Codeausschnitt entspricht:

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

Sie müssen außerdem am Anfang der Datei TableServiceConfig.java die folgende Using-Anweisung hinzufügen.

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

6. Implementieren von Azure Cosmos DB-Tabellenvorgängen

Alle Azure Cosmos DB-Tabellenvorgänge für die Beispiel-App werden in der TablesServiceImpl-Klasse implementiert, die sich im Verzeichnis Services befindet. Sie müssen das SDK-Paket com.azure.data.tables importieren.

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;

Fügen Sie am Anfang der TableServiceImpl-Klasse eine Membervariable für das TableClient-Objekt und einen Konstruktor hinzu, damit das TableClient-Objekt in die Klasse eingefügt werden kann.

@Autowired
private TableClient tableClient;

Abrufen von Zeilen aus einer Tabelle

Die TableClient-Klasse enthält eine Methode namens listEntities, mit der Sie Zeilen aus der Tabelle auswählen können. Da in diesem Beispiel keine Parameter an die Methode übergeben werden, werden alle Zeilen in der Tabelle ausgewählt.

Die Methode nimmt auch einen generischen Parameter vom Typ TableEntity an, der angibt, als welche Modellklasse die Daten zurückgegeben werden. In diesem Fall wird die integrierte Klasse TableEntity verwendet, was bedeutet, dass die listEntities-Methode eine PagedIterable<TableEntity>-Sammlung als Ergebnis zurückgibt.

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

Die im Paket com.azure.data.tables.models definierte Klasse TableEntity verfügt über Eigenschaften für die Partitionsschlüssel- und Zeilenschlüsselwerte in der Tabelle. Zusammen bilden diese beiden Werte einen eindeutigen Schlüssel für die Zeile in der Tabelle. In dieser Beispielanwendung wird der Name der Wetterstation (Stadt) im Partitionsschlüssel gespeichert, und das Datum bzw. die Uhrzeit der Beobachtung wird im Zeilenschlüssel gespeichert. Alle anderen Eigenschaften (Temperatur, Luftfeuchtigkeit, Windgeschwindigkeit) werden in einem Wörterbuch im TableEntity-Objekt gespeichert.

Es ist üblich, ein TableEntity-Objekt einem Objekt Ihrer eigenen Definition zuzuordnen. Die Beispielanwendung definiert zu diesem Zweck eine WeatherDataModel-Klasse im Verzeichnis Models. Diese Klasse verfügt über Eigenschaften für den Stationsnamen und das Beobachtungsdatum, denen der Partitionsschlüssel und der Zeilenschlüssel zugeordnet wird, und bietet aussagekräftigere Eigenschaftsnamen für diese Werte. Anschließend wird ein Wörterbuch verwendet, um alle anderen Eigenschaften des Objekts zu speichern. Dies ist ein gängiges Muster bei der Arbeit mit Tabellenspeicher, da eine Zeile eine beliebige Anzahl von Eigenschaften aufweisen kann und wir möchten, dass unsere Modellobjekte in der Lage sind, alle diese Eigenschaften zu erfassen. Diese Klasse enthält auch Methoden zum Auflisten der Eigenschaften für die Klasse.

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

Die mapTableEntityToWeatherDataModel-Methode wird verwendet, um ein TableEntity-Objekt einem WeatherDataModel-Objekt zuzuordnen. Die mapTableEntityToWeatherDataModel-Methode ordnet die Eigenschaften PartitionKey, RowKey, Timestamp und Etag direkt zu und verwendet dann properties.keySet, um über die anderen Eigenschaften im Objekt TableEntity zu iterieren und diese dem Objekt WeatherDataModel zuzuordnen, abzüglich der Eigenschaften, die bereits direkt zugeordnet wurden.

Bearbeiten Sie den Code in der mapTableEntityToWeatherDataModel-Methode so, dass er dem folgenden Codeblock entspricht.

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

Filtern von Zeilen, die von einer Tabelle zurückgegeben werden

Um die von einer Tabelle zurückgegebenen Zeilen zu filtern, können Sie eine Filterzeichenfolge im OData-Stil an die listEntities-Methode übergeben. Wenn Sie beispielsweise alle Wetterwerte für Chicago zwischen 1. Juli 2021 Mitternacht und 2. Juli 2021 Mitternacht (einschließlich) abrufen möchten, übergeben Sie die folgende Filterzeichenfolge.

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

Sie können alle OData-Filteroperatoren auf der OData-Website im Abschnitt Filter System Query Option (Systemabfrageoption filtern) anzeigen.

In der Beispielanwendung ist das FilterResultsInputModel-Objekt so konzipiert, dass alle vom Benutzer bereitgestellten Filterkriterien erfasst werden.

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

Wenn dieses Objekt an die retrieveEntitiesByFilter-Methode in der TableServiceImpl-Klasse übergeben wird, wird eine Filterzeichenfolge für jeden Eigenschaftswert erstellt, der nicht NULL ist. Anschließend wird eine kombinierte Filterzeichenfolge erstellt, indem alle Werte mit einer „and“-Klausel verbunden werden. Diese kombinierte Filterzeichenfolge wird an die listEntities-Methode für das TableClient-Objekt übergeben, und nur Zeilen, die der Filterzeichenfolge entsprechen, werden zurückgegeben. Sie können eine ähnliche Methode in Ihrem Code verwenden, um für Ihre Anwendung erforderliche geeignete Filterzeichenfolgen zu erstellen.

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

Einfügen von Daten mithilfe eines TableEntity-Objekts

Die einfachste Möglichkeit zum Hinzufügen von Daten zu einer Tabelle ist die Verwendung eines TableEntity-Objekts. In diesem Beispiel werden Daten aus einem Eingabemodellobjekt einem TableEntity-Objekt zugeordnet. Die Eigenschaften des Eingabeobjekts, die den Namen der Wetterstation und das Datum/die Uhrzeit der Beobachtung darstellen, werden den Eigenschaften PartitionKey bzw. RowKey zugeordnet, die zusammen einen eindeutigen Schlüssel für die Zeile in der Tabelle bilden. Anschließend werden die zusätzlichen Eigenschaften des Eingabemodellobjekts Wörterbucheigenschaften für das TableClient-Objekt zugeordnet. Schließlich wird die createEntity-Methode für das TableClient-Objekt verwendet, um Daten in die Tabelle einzufügen.

Ändern Sie die insertEntity-Klasse in der Beispielanwendung so, dass sie den folgenden Code enthält.

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

Ausführen eines Upserts von Daten mithilfe eines TableEntity-Objekts

Wenn Sie versuchen, eine Zeile in eine Tabelle mit einer Kombination aus Partitionsschlüssel und Zeilenschlüssel einzufügen, die bereits in dieser Tabelle vorhanden ist, erhalten Sie einen Fehler. Aus diesem Grund ist es häufig vorzuziehen, beim Hinzufügen von Zeilen zu einer Tabelle upsertEntity anstelle der insertEntity-Methode zu verwenden. Wenn die angegebene Kombination aus Partitionsschlüssel und Zeilenschlüssel bereits in der Tabelle vorhanden ist, aktualisiert die upsertEntity-Methode die vorhandene Zeile. Andernfalls wird die Zeile der Tabelle hinzugefügt.

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

Einfügen oder Upsert von Daten mit variablen Eigenschaften

Einer der Vorteile der Tabellen-API von Azure Cosmos DB besteht darin, dass, wenn ein Objekt, das in eine Tabelle geladen wird, neue Eigenschaften enthält, diese Eigenschaften automatisch der Tabelle hinzugefügt und die Werte in Azure Cosmos DB gespeichert werden. Es besteht keine Notwendigkeit, DDL-Anweisungen wie ALTER TABLE auszuführen, um Spalten hinzuzufügen, wie es bei einer herkömmlichen Datenbank der Fall ist.

Dieses Modell bietet Ihrer Anwendung Flexibilität beim Umgang mit Datenquellen, die im Laufe der Zeit Daten hinzufügen oder ändern können, oder wenn unterschiedliche Eingaben unterschiedliche Daten für Ihre Anwendung bereitstellen. In der Beispielanwendung können wir eine Wetterstation simulieren, die nicht nur die Basiswetterdaten, sondern auch einige zusätzliche Werte sendet. Wenn ein Objekt mit diesen neuen Eigenschaften zum ersten Mal in der Tabelle gespeichert wird, werden der Tabelle automatisch die entsprechenden Eigenschaften (Spalten) hinzugefügt.

In der Beispielanwendung basiert die ExpandableWeatherObject-Klasse auf einem internen Wörterbuch, um alle Eigenschaften des Objekts zu unterstützen. Diese Klasse stellt ein typisches Muster für den Fall dar, dass ein Objekt einen beliebigen Satz von Eigenschaften enthalten muss.

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

Um ein solches Objekt mit der API für Table einzufügen oder ein Upsert auszuführen, ordnen Sie die Eigenschaften des erweiterbaren Objekts einem TableEntity-Objekt zu und verwenden die createEntity- bzw. upsertEntity-Methode für das TableClient-Objekt.

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

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

Aktualisieren einer Entität

Entitäten können aktualisiert werden, indem die updateEntity-Methode für das TableClient-Objekt aufgerufen wird. Da eine Entität (Zeile), die mit der Tabellen-API gespeichert wird, beliebige Eigenschaften enthalten kann, ist es häufig hilfreich, ein Aktualisierungsobjekt zu erstellen, das auf einem Wörterbuchobjekt basiert, das dem zuvor beschriebenen ExpandableWeatherObject ähnelt. In diesem Fall besteht der einzige Unterschied im Hinzufügen einer etag-Eigenschaft, die bei Aktualisierungen für Parallelitätssteuerung verwendet wird.

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

In der Beispiel-App wird dieses Objekt an die updateEntity-Methode in der TableServiceImpl-Klasse übergeben. Diese Methode lädt zuerst die vorhandene Entität aus der Tabellen-API, indem die getEntity-Methode für den TableClient verwendet wird. Anschließend wird dieses Entitätsobjekt aktualisiert und die updateEntity-Methode verwendet, um die Aktualisierungen in der Datenbank zu speichern. Beachten Sie, wie die updateEntity-Methode das aktuelle Etag des Objekts verwendet, um sicherzustellen, dass sich das Objekt seit dem ersten Laden nicht geändert hat. Wenn Sie die Entität unabhängig davon aktualisieren möchten, können Sie den Wert etag an die updateEntity-Methode übergeben.

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

Entfernen einer Entität

Um eine Entität aus einer Tabelle zu entfernen, rufen Sie die deleteEntity-Methode für das TableClient-Objekt mit dem Partitionsschlüssel und Zeilenschlüssel des Objekts auf.

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

7\. Ausführen des Codes

Führen Sie die Beispielanwendung aus, um mit der Tabellen-API von Azure Cosmos DB zu interagieren. Wenn Sie die Anwendung zum ersten Mal ausführen, sind keine Daten vorhanden, weil die Tabelle leer ist. Verwenden Sie eine der Schaltflächen oben in der Anwendung, um der Tabelle Daten hinzuzufügen.

Screenshot: Anwendung mit der Position der Schaltflächen zum Einfügen von Daten in Azure Cosmos DB mit der API für Table

Wenn Sie die Schaltfläche Insert using Table Entity (Mit Tabellenentität einfügen) auswählen, wird ein Dialogfeld geöffnet, in dem Sie eine neue Zeile mithilfe eines TableEntity-Objekts einfügen oder ein Upsert ausführen können.

Screenshot: Anwendung mit dem Dialogfeld zum Einfügen von Daten mithilfe eines TableEntity-Objekts.

Wenn Sie auf die Schaltfläche Insert using Expandable Data (Mit erweiterbaren Daten einfügen) klicken, wird ein Dialogfeld geöffnet, in dem Sie ein Objekt mit benutzerdefinierten Eigenschaften einfügen können. Dies zeigt, wie die Tabellen-API von Azure Cosmos DB der Tabelle bei Bedarf automatisch Eigenschaften (Spalten) hinzufügt. Verwenden Sie die Schaltfläche Add Custom Field (Benutzerdefiniertes Feld hinzufügen), um mindestens eine neue Eigenschaft hinzuzufügen und diese Funktion zu veranschaulichen.

Screenshot: Anwendung mit dem Dialogfeld zum Einfügen von Daten mithilfe eines Objekts mit benutzerdefinierten Feldern.

Verwenden Sie die Schaltfläche Insert Sample Data (Beispieldaten einfügen), um einige Beispieldaten in Ihre Azure Cosmos DB-Tabelle zu laden.

Screenshot: Anwendung mit der Position der Schaltfläche zum Einfügen von Beispieldaten.

Wählen Sie im oberen Menü das Element Filter Results (Filterergebnisse) aus, um zur Seite „Filter Results“ zu gelangen. Füllen Sie auf dieser Seite die Filterkriterien aus, um zu zeigen, wie eine Filterklausel erstellt und an die Tabellen-API von Azure Cosmos DB übergeben werden kann.

Screenshot: Anwendung mit der Seite „Filterergebnisse“ und Hervorhebung des Menüelements, das zum Navigieren zur Seite verwendet wird.

Bereinigen von Ressourcen

Wenn Sie die Beispielanwendung abgeschlossen haben, sollten Sie alle Azure-Ressourcen im Zusammenhang mit diesem Artikel aus Ihrem Azure-Konto entfernen. Sie können dazu die Ressourcengruppe löschen.

Eine Ressourcengruppe kann über das Azure-Portal wie folgt gelöscht werden.

Anweisungen Screenshot
Um zur Ressourcengruppe zu wechseln, geben Sie auf der Suchleiste den Namen der Ressourcengruppe ein. Wählen Sie dann auf der Registerkarte Ressourcengruppen den Namen der Ressourcengruppe aus. Screenshot: Suchen nach einer Ressourcengruppe.
Wählen Sie oben auf der Seite „Ressourcengruppe“ auf der Symbolleiste die Option Ressourcengruppe löschen aus. Screenshot: Position der Schaltfläche „Ressourcengruppe löschen“.
Rechts auf dem Bildschirm wird ein Dialogfeld angezeigt, in dem Sie aufgefordert werden, das Löschen der Ressourcengruppe zu bestätigen.
  1. Geben Sie den vollständigen Namen der Ressourcengruppe in das Textfeld ein, um das Löschen zu bestätigen.
  2. Wählen Sie am unteren Rand der Seite die Schaltfläche Löschen aus.
Screenshot: Bestätigungsdialogfeld zum Löschen einer Ressourcengruppe.

Nächste Schritte

In diesem Schnellstart haben Sie gelernt, wie Sie ein Azure Cosmos DB-Konto erstellen, eine Tabelle mit dem Daten-Explorer erstellen und eine App ausführen. Jetzt können Sie Ihre Daten mithilfe der API für Table abfragen.