التشغيل السريع: إنشاء واجهة برمجة تطبيقات لتطبيق Table باستخدام Java SDK وAzure Cosmos DB

ينطبق على: جدول

يوضح هذا التشغيل السريع كيفية الوصول إلى Azure Cosmos DB Table API من تطبيق Java. واجهة برمجة تطبيقات جداول Azure Cosmos DB هي مخزن بيانات بلا مخطط يسمح للتطبيقات بتخزين بيانات NoSQL المنظمة في السحابة. لأنه يتم تخزين البيانات في تصميم بلا مخطط، يتم إضافة خصائص (أعمدة) جديدة تلقائياً إلى الجدول عند إضافة كائن بسمة جديدة إلى الجدول.

يمكن لتطبيقات Java الوصول إلى Azure Cosmos DB Tables API باستخدام مكتبة عميل azure-data-tables .

المتطلبات الأساسية

تتم كتابة نموذج التطبيق في Spring Boot 2.6.4، يمكنك استخدام إما التعليمة البرمجية لـ Visual Studio أو IntelliJ IDEA كبيئة تطوير متكاملة IDE.

في حال لم يكن لديك اشتراك في Azure، قم بإنشاءحساب مجاني قبل البدء.

عينات التطبيقات

قد يتم استنساخ نموذج التطبيق لهذا البرنامج التعليمي أو تنزيله من المستودع https://github.com/Azure-Samples/msdocs-azure-data-tables-sdk-java. يتم تضمين كل من تطبيق البداية والتطبيق المكتمل في مستودع النموذج.

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

يستخدم نموذج التطبيق بيانات الطقس كمثال توضيحي لإمكانيات واجهة برمجة تطبيقات الجدول. يتم تخزين الكائنات التي تمثل ملاحظات الطقس واستردادها باستخدام واجهة برمجة التطبيقات للجدول، بما في ذلك تخزين الكائنات بخصائص إضافية لتوضيح قدرات واجهة برمجة تطبيقات الجداول بدون مخطط.

لقطة شاشة للتطبيق النهائي تعرض البيانات المخزنة في جدول Azure Cosmos DB باستخدام Table API.

1 - إنشاء حساب على Azure Cosmos DB

تحتاج أولا إلى إنشاء حساب Azure Cosmos DB Tables API الذي سيحتوي على الجدول (الجداول) المستخدمة في التطبيق الخاص بك. يمكن إجراء ذلك باستخدام مدخل Microsoft Azure أو Azure CLI أو Azure PowerShell.

سجل الدخول إلى مدخل Microsoft Azure واتبع هذه الخطوات لإنشاء حساب Azure Cosmos DB.

الإرشادات لقطة شاشة
في مدخل Microsoft Azure:
  1. في شريط البحث أعلى مدخل Microsoft Azure، أدخل "Azure Cosmos DB".
  2. في القائمة التي تظهر أسفل شريط البحث، ضمن Services، حدد العنصر المسمى Azure Cosmos DB.
لقطة شاشة توضح كيفية استخدام مربع البحث في شريط الأدوات العلوي للعثور على حسابات Azure Cosmos DB في Azure.
في الصفحة ⁧⁩Azure Cosmos DB⁧⁩، حدد ⁧⁩إنشاء⁧⁩. لقطة شاشة تعرض موقع الزر Create في صفحة حسابات Azure Cosmos DB في Azure.
في الصفحة خيار تحديد واجهة برمجة التطبيقات، اختر الخيار جدول Azure. لقطة شاشة تعرض خيار Azure Table كخيار صحيح للتحديد.
على صفحة إنشاء حساب Azure Cosmos DB - جدول Azure، قم بتعبئة النموذج كما يلي.
  1. قم بإنشاء مجموعة موارد جديدة لحساب التخزين المسمى rg-msdocs-tables-sdk-demo عن طريق تحديد الارتباط إنشاء جديد ضمن مجموعة الموارد.
  2. امنح حساب التخزين الخاص بك اسم cosmos-msdocs-tables-sdk-demo-XYZ، حيث تكون XYZ هي أي ثلاثة أحرف عشوائية لإنشاء اسم حساب فريد. يجب أن يتراوح طول أسماء حسابات Azure Cosmos DB من 3 إلى 44 حرفاً، وقد تحتوي على أحرف صغيرة أو أرقام أو واصلة (-) فقط.
  3. حدد المنطقة لحساب التخزين الخاص بك.
  4. حدد الأداء القياسي.
  5. حدد معدل النقل المزود لهذا المثال ضمن وضع السعة.
  6. حدد تطبيق ضمن تطبيق خصم مستوى مجاني لهذا المثال.
  7. حدد الزر مراجعة + إنشاء في أسفل الشاشة ثم حدد "إنشاء" على شاشة الملخص لإنشاء حساب Azure Cosmos DB. قد تستغرق هذه العملية عدة دقائق.
لقطة شاشة توضح كيفية ملء الحقول في صفحة إنشاء حساب Azure Cosmos DB.

2 - إنشاء جدول

بعد ذلك، تحتاج إلى إنشاء جدول داخل حساب Azure Cosmos DB الخاص بك لاستخدام التطبيق الخاص بك. بعكس قاعدة بيانات تقليدية، تحتاج فقط إلى تحديد اسم الجدول، وليس الخصائص (الأعمدة) في الجدول. مع تحميل البيانات في الجدول، سيتم إنشاء الخصائص (الأعمدة) تلقائياً حسب الحاجة.

في مدخل Microsoft Azure، أكمل الخطوات التالية لإنشاء جدول داخل حساب Azure Cosmos DB الخاص بك.

الإرشادات لقطة شاشة
في مدخل Microsoft Azure، انتقل إلى صفحة النظرة العامة لحساب Azure Cosmos DB. يمكنك الانتقال إلى صفحة النظرة العامة لحساب Azure Cosmos DB الخاص بك عن طريق كتابة اسم (cosmos-msdocs-tables-sdk-demo-XYZ) لحساب Azure Cosmos DB في شريط البحث العلوي والبحث تحت عنوان الموارد. حدد اسم حساب Azure Cosmos DB للانتقال إلى صفحة النظرة العامة. لقطة شاشة توضح كيفية استخدام مربع البحث في شريط الأدوات العلوي للعثور على حساب Azure Cosmos DB الخاص بك.
في صفحة النظرة العامة، حدد +إضافة جدول. سيتم تمرير مربع الحوار «جدول جديد» من الجانب الأيسر من الصفحة. لقطة شاشة توضح موقع الزر
في مربع الحوار New Table، بادر بتعبئة النموذج على النحو التالي.
  1. أدخِل اسم WeatherData لمُعرف الجدول. هذا هو اسم الجدول.
  2. حدد Manual ضمن Table throughput (autoscale) لهذا المثال.
  3. استخدم القيمة الافتراضية 400 ضمن وحدة الطلب/ ثانية المُقدرة خاصتك.
  4. حدد الزر OK لإنشاء الجدول.
لقطة شاشة توضح مربع الحوار

3 - الحصول على Azure Cosmos DB سلسلة الاتصال

للوصول إلى الجدول (الجداول) في Azure Cosmos DB، سيحتاج تطبيقك إلى سلسلة الاتصال الجدول لحساب CosmosDB Storage. يمكن استرداد سلسلة الاتصال باستخدام مدخل Microsoft Azure أو Azure CLI أو Azure PowerShell.

الإرشادات لقطة شاشة
على الجانب الأيمن من صفحة حساب Azure Cosmos DB، حدد موقع عنصر القائمة المسمى سلسلة الاتصال ضمن عنوان الإعدادات وحدده. سيتم نقلك إلى صفحة حيث يمكنك استرداد سلسلة الاتصال لحساب التخزين. لقطة شاشة تعرض موقع ارتباط سلسلة الاتصال على صفحة Azure Cosmos DB.
انسخ قيمة سلسلة الاتصال الأساسية لاستخدامها في التطبيق الخاص بك. لقطة شاشة توضح سلسلة الاتصال المراد تحديدها واستخدامها في التطبيق.

يعتبر سلسلة الاتصال لحساب Azure Cosmos DB سر تطبيق ويجب حمايته مثل أي سر أو كلمة مرور أخرى للتطبيق. يستخدم هذا المثال POM لتخزين سلسلة الاتصال أثناء التطوير وجعلها متوفرة للتطبيق.

<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 - تضمين حزمة جداول البيانات azure

للوصول إلى Azure Cosmos DB Tables API من تطبيق Java، قم بتضمين حزمة azure-data-tables .

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

5 - تكوين عميل Table في TableServiceConfig.java

تتصل Azure SDK بـ Azure باستخدام كائنات العميل لتنفيذ عمليات مختلفة على أساس Azure. كائن TableClient هو الكائن المستخدم للاتصال بواجهة برمجة تطبيقات جداول Azure Cosmos DB.

سينشئ أحد التطبيقات عادة كائن TableClient واحداً لكل جدول لاستخدامه في التطبيق كله. من المهم معرفة أن هذا الأسلوب ينتج عنه عناصر مكونة لـ TableClient تدار من حاوية Spring كقاعدة بيانات أحادية لإتمام العملية.

في TableServiceConfig.javaملف التطبيق، حرر tableClientConfiguration() أسلوب مطابقة القصاصة البرمجية التالية:

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

ستحتاج أيضاً إلى إضافة عبارة الاستخدام التالية في الجزء العلوي من ملف TableServiceConfig.java.

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

6 - تنفيذ عمليات جدول Azure Cosmos DB

يتم تنفيذ جميع عمليات جدول Azure Cosmos DB لنموذج التطبيق في TablesServiceImpl الفئة الموجودة في دليل الخدمات . ستحتاج لاستيراد حزمة 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;

في بداية فئة TableServiceImpl، أضف متغير عضو لكائن TableClient ودالة إنشائية للسماح بحقن كائن TableClient في الفئة.

@Autowired
private TableClient tableClient;

الحصول على صفوف من جدول

تحتوي فئة TableClient على أسلوب يسمى listEntities الذي يسمح لك بتحديد صفوف من الجدول. في هذا المثال، نظراً لعدم تمرير أية معلمات إلى الأسلوب، سيتم تحديد جميع الصفوف من الجدول.

ويستخدم هذا الأسلوب أيضاً معلمة عامة من نوع TableEntity يُحدد بيانات فئة النموذج التي سيتم استرجاعها. في هذه الحالة، يتم استخدام الفئة المضمنة TableEntity، مما يعني أن أسلوب listEntities سيُرجِع مجموعة PagedIterable<TableEntity> كنتائج له.

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

تحتوي فئة TableEntity المحددة في حزمة com.azure.data.tables.models على خصائص لقيم مفتاح القسم ومفتاح الصف في الجدول. تكون هاتان القيمتان معاً لمفتاح فريد للصف في الجدول. في هذا المثال على التطبيق، يتم تخزين اسم محطة الطقس (المدينة) في مفتاح القسم، ويتم تخزين تاريخ/وقت الملاحظة في مفتاح الصف. يتم تخزين جميع الخصائص الأخرى (درجة الحرارة والرطوبة وسرعة الرياح) في قاموس في كائن TableEntity.

من الممارسات الشائعة تعيين عنصر TableEntity إلى عنصر من تعريف خاص بك. يحدد نموذج التطبيق فئة WeatherDataModel في دليل Models لهذا الغرض. تحتوي هذه الفئة على خصائص اسم المحطة وتاريخ الملاحظة الذي سيتم تعيين مفتاح القسم ومفتاح الصف إليه، ما يوفر أسماء خصائص ذات معنى أكبر لهذه القيم. ثم تستخدم قاموساً لتخزين جميع الخصائص الأخرى في الكائن. هذا نمط شائع عند استخدام مخزن الجداول حيث يمكن أن يكون للصف أي عدد من الخصائص العشوائية ونريد أن تكون كائنات النموذج لدينا قادرة على تسجيل كل منها. تحتوي هذه الفئة أيضاً على أساليب لسرد الخصائص في الفئة.

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

يتم استخدام أسلوب mapTableEntityToWeatherDataModel لتعيين كائن TableEntity إلى كائن WeatherDataModel. يعين أسلوب mapTableEntityToWeatherDataModel خصائص PartitionKey وRowKey وTimestamp وEtag مباشرة، ثم يستخدم خاصية properties.keySet للتكرار في الخصائص الأخرى في عنصر TableEntity ويعين تلك الخصائص إلى العنصر WeatherDataModel، مطروحاً منها الخصائص التي تم تعيينها مباشرة من قبل.

حرر التعليمات البرمجية في أسلوب mapTableEntityToWeatherDataModel لمطابقة كتلة التعليمات البرمجية التالية.

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

تصفية الصفوف التي يتم إرجاعها من جدول

لتصفية الصفوف التي يتم إرجاعها من جدول، يمكنك تمرير سلسلة عامل تصفية نمط OData إلى أسلوب listEntities. على سبيل المثال، إذا أردت الحصول على جميع قراءات الطقس لمدينة شيكاغو بين منتصف ليل 1 يوليو 2021 ومنتصف ليل 2 يوليو 2021 (شاملة)، فستمر في سلسلة التصفية التالية.

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

يمكنك عرض جميع عوامل تشغيل تصفية OData على موقع OData على الويب في قسم خيار استعلام نظام التصفية

في مثال التطبيق، تم تصميم كائن FilterResultsInputModel لتسجيل أية معايير تصفية يوفرها المستخدم.

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

عند تمرير هذا الكائن إلى أسلوب retrieveEntitiesByFilter في فئة TableServiceImpl، ينشئ سلسلة تصفية لكل قيمة خاصية غير خالية. ثم ينشئ سلسلة تصفية مجمعة عن طريق ربط جميع القيم مع عبارة "and". يتم تمرير سلسلة التصفية المجمعة هذه إلى أسلوب listEntities في عنصر TableClient ويتم إرجاع الصفوف المطابقة لسلسلة التصفية فقط. يمكنك استخدام أسلوب مشابه في التعليمات البرمجية لإنشاء سلاسل تصفية مناسبة كما هو مطلوب من تطبيقك.

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

إدراج بيانات باستخدام كائن TableEntity

أبسط طريقة لإضافة بيانات إلى جدول هي استخدام كائن TableEntity. في هذا المثال، يتم تعيين البيانات من كائن نموذج إدخال إلى كائن TableEntity. يتم تعيين الخصائص الموجودة في عنصر الإدخال الذي يمثل اسم محطة الطقس وتاريخ/وقت الملاحظة إلى خاصيتي PartitionKey وRowKey) على التوالي؛ ويشكلان معاً مفتاحاً فريداً للصف في الجدول. تُعين خصائص إضافية في عنصر نموذج الإدخال إلى خصائص القاموس في عنصر TableEntity. وأخيراً، يستخدم أسلوب createEntity في عنصر TableClient لإدراج البيانات في الجدول.

عدِّل فئة insertEntity في مثال التطبيق لاحتواء التعليمات البرمجية التالية.

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

تحديث/إدراج البيانات باستخدام كائن TableEntity

إذا حاولت إدراج صف في جدول باستخدام تركيبة مفتاح قسم/مفتاح صف موجودة حاليا في هذا الجدول، فسيظهر لك خطأ. لهذا السبب، يفضل غالباً استخدام UpsertEntity بدلاً من أسلوب insertEntityعند إضافة صفوف إلى جدول. إذا كانت تركيبة مفتاح القسم /مفتاح الصف المحددة موجودة حالياً في الجدول، فإن الأسلوب UpsertEntity سيُحدِّث الصف الموجود. وإلا، فسيتم إضافة الصف إلى الجدول.

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

إدراج بيانات ذات خصائص متغيرة أو تحديثها/إدراجها

تتمثل إحدى مزايا استخدام Azure Cosmos DB Tables API في أنه إذا كان العنصر الذي يتم تحميله إلى جدول يحتوي على أي خصائص جديدة، فستضاف هذه الخصائص تلقائيا إلى الجدول والقيم المخزنة في Azure Cosmos DB. ليست هناك حاجة لتشغيل عبارات لغة تعريف البيانات (DDL)، مثل ALTER TABLE لإضافة أعمدة كما يحدث في قاعدة البيانات التقليدية.

يمنح هذا النموذج المرونة للتطبيق عند التعامل مع مصادر البيانات التي قد تضيف أو تعدل البيانات التي تحتاج إلى تسجيلها بمرور الوقت أو عندما توفر مدخلات مختلفة بيانات مختلفة للتطبيق. في نموذج التطبيق، يمكننا محاكاة محطة الطقس التي ترسل ليس فقط بيانات الطقس الأساسية، ولكن أيضاً بعض القيم الإضافية. عند تخزين كائن بهذه الخصائص الجديدة في الجدول للمرة الأولى، ستتم إضافة الخصائص المطابقة (الأعمدة) تلقائياً إلى الجدول.

في نموذج التطبيق، يتم إنشاء فئة ExpandableWeatherObject حول قاموس داخلي لدعم أي مجموعة من الخصائص في الكائن. تمثل هذه الفئة نمطاً نموذجياً عندما يتعين احتواء كائن على مجموعة عشوائية من الخصائص.

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

لإدراج مثل هذا الكائن أو رفعه باستخدام واجهة برمجة التطبيقات للجدول، قم بتعيين خصائص الكائن القابل للتوسيع في كائن TableEntity واستخدم أساليب createEntity أو upsertEntity على كائن TableClient حسب الاقتضاء.

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

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

تحديث كيان

يمكن تحديث العناصر عن طريق استدعاء أسلوب UpdateEntity في عنصر TableClient. من المفيد إنشاء عنصر تحديث يعتمد على عنصر قاموسي مشابهاً لـ ExpandableWeatherObject الذي ناقشناه سابقا وذلك لأن الكيان (الصف) الذي تم تخزينه باستخدام Table API قد يحتوي على مجموعة عشوائية من الخصائص. في هذه الحالة، يكون الفرق الوحيد هو إضافة خاصية etag التي يتم استخدامها للتحكم في التزامن أثناء التحديثات.

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

في نموذج التطبيق، يتم تمرير هذا الكائن إلى أسلوب updateEntity في فئة TableServiceImpl. يعمل هذا الأسلوب أولاً على تحميل الكيان الموجود من Table API باستخدام أسلوب GetEntity في TableClient. ثم يعمل على تحديث كائن الكيان هذا ويستخدم أسلوب updateEntity حفظ التحديثات بقاعدة البيانات. لاحظ كيف يأخذ أسلوب UpdateEntity ‏Etag الحالية للعنصر لضمان عدم حدوث تغيير للعنصر منذ تحميله أول مرة. إذا كنت تريد تحديث الكيان بغض النظر عن ذلك، يمكنك تمرير قيمة etag إلى أسلوب 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);
}

إزالة كيان

لإزالة عنصر من جدول، استدعِ أسلوب deleteEntity في عنصر TableClient بمفتاح القسم ومفتاح الصف الخاص بالعنصر.

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

7 - تشغيل التعليمات البرمجية

تشغيل نموذج التطبيق للتفاعل مع Azure Cosmos DB Tables API. في المرة الأولى التي تشغِّل فيها التطبيق، لن يكون هناك بيانات لأن الجدول فارغ. استخدم أياً من الأزرار الموجودة في الجزء العلوي من التطبيق لإضافة بيانات إلى الجدول.

لقطة شاشة للتطبيق تعرض موقع الأزرار المستخدمة لإدراج البيانات في Azure Cosmos DB باستخدام Table API.

يؤدي تحديد الزر Insert using Table Entity إلى فتح مربع حوار يسمح لك بإدراج أو تحديث/إدراج صف جديد باستخدام كائن TableEntity.

لقطة شاشة للتطبيق تعرض مربع الحوار المستخدم لإدراج البيانات باستخدام عنصر TableEntity.

يؤدي تحديد الزر إدراج باستخدام بيانات قابلة للتوسيع إلى إحضار مربع حوار يمكنك من إدراج كائن بخصائص مخصصة، مما يوضح كيف تضيف واجهة برمجة تطبيقات جداول Azure Cosmos DB تلقائيا خصائص (أعمدة) إلى الجدول عند الحاجة. استخدم الزر Add Custom Field لإضافة خاصية جديدة واحدة أو أكثر وإظهار هذه الإمكانية.

لقطة شاشة للتطبيق تعرض مربع الحوار المستخدم لإدراج البيانات باستخدام عنصر مع حقول مخصصة.

استخدم الزر Insert Sample Data لتحميل بعض بيانات العينة في جدول Azure Cosmos DB.

لقطة شاشة للتطبيق توضح موقع زر إدخال بيانات العينة.

حدد عنصر Filter Results في القائمة العلوية ليتم نقله إلى صفحة "Filter Results". في هذه الصفحة، املأ معايير التصفية لتوضيح كيفية إنشاء عبارة عامل تصفية وتميرها إلى واجهة برمجة تطبيقات جداول Azure Cosmos DB.

لقطة شاشة للتطبيق تعرض صفحة نتائج التصفية وتبرز عنصر القائمة المستخدم للانتقال إلى الصفحة.

تنظيف الموارد

عند الانتهاء من نموذج التطبيق، يجب إزالة جميع موارد Azure الخاصة بهذه المقالة من حسابك على Azure. يمكنك إجراء ذلك عن طريق حذف مجموعة الموارد.

يمكن حذف مجموعة موارد باستخدام مدخل Microsoft Azure عن طريق إجراء ما يلي.

الإرشادات لقطة شاشة
للانتقال إلى مجموعة الموارد، في شريط البحث، اكتب اسم مجموعة الموارد. ثم في علامة التبويب Resource Groups، حدد اسم مجموعة الموارد. لقطة شاشة توضح كيفية البحث عن مجموعة موارد.
حدد Delete resource group من شريط الأدوات أعلى صفحة مجموعة الموارد. لقطة شاشة توضح موقع زر حذف مجموعة الموارد.
سيظهر مربع حوار من يمين الشاشة يطلب منك تأكيد حذف مجموعة الموارد.
  1. اكتب الاسم الكامل لمجموعة الموارد في مربع النص لتأكيد الحذف على النحو المحدد.
  2. اضغط الزر Delete أسفل الصفحة.
لقطة شاشة تعرض مربع حوار التأكيد لحذف مجموعة موارد.

الخطوات التالية

في هذه البداية السريعة، تعلمت كيفية إنشاء حساب Azure Cosmos DB، وإنشاء جدول باستخدام مستكشف البيانات، وتشغيل تطبيق. يمكنك الآن الاستعلام عن بياناتك باستخدام واجهة برمجة التطبيقات للجدول.