Mengelola grafik kembar digital menggunakan hubungan

Jantung Azure Digital Twins adalah grafik kembar yang mewakili seluruh lingkungan Anda. Grafik kembar terbuat dari kembar digital individu yang terhubung melalui hubungan. Artikel ini berfokus pada pengelolaan hubungan dan grafik secara keseluruhan; untuk bekerja dengan masing-masing kembar digital, lihat Mengelola kembar digital.

Setelah Anda memiliki instans Azure Digital Twins yang berfungsi dan telah menyiapkan kode autentikasi di aplikasi klien Anda, Anda dapat membuat, memodifikasi, dan menghapus kembar digital dan hubungan mereka dalam instans Azure Digital Twins.

Prasyarat

Untuk bekerja dengan Azure Digital Twins dalam artikel ini, Anda memerlukan instans Azure Digital Twins dan izin yang diperlukan untuk menggunakannya. Jika Anda sudah menyiapkan instans Azure Digital Twins, Anda dapat menggunakan instans tersebut dan melompat ke bagian berikutnya. Jika tidak, ikuti instruksi dalam Menyiapkan instans dan autentikasi. Instruksi berisi informasi untuk membantu Anda memverifikasi bahwa Anda telah menyelesaikan setiap langkah dengan sukses.

Setelah Anda menyiapkan instans, catat nama host instans. Anda dapat menemukan nama host di portal Microsoft Azure.

Antarmuka pengembang

Artikel ini menyoroti cara menyelesaikan berbagai operasi pengelolaan menggunakan .NET (C#) SDK. Anda juga dapat membuat panggilan pengelolaan yang sama ini menggunakan SDK bahasa lain yang dijelaskan di Azure Digital Twins API dan SDK.

Antarmuka pengembang lain yang dapat digunakan untuk menyelesaikan operasi ini meliputi:

Visualisasi

Azure Digital Twins Explorer adalah alat visual untuk menjelajahi data di grafik Azure Digital Twins Anda. Anda bisa menggunakan explorer untuk menampilkan, mengkueri, dan mengedit model, twin, dan hubungan Anda.

Baca Alat Penjelajah Azure Digital Twins di Penjelajah Azure Digital Twins. Untuk langkah-langkah mendetail tentang cara menggunakan fiturnya, lihat Menggunakan Penjelajah Azure Digital Twins.

Berikut tampilan visualisasinya:

Screenshot of Azure Digital Twins Explorer showing sample models and twins.

Buat hubungan

Hubungan menggambarkan perbedaan kembar digital terhubung satu sama lain, yang membentuk dasar grafik kembar.

Jenis hubungan yang dapat dibuat dari satu (sumber) kembar ke kembar (target) lain didefinisikan sebagai bagian dari model DTDL kembar sumber. Anda dapat membuat instans hubungan dengan menggunakan panggilan SDK dengan kembar CreateOrReplaceRelationshipAsync() dan detail hubungan yang mengikuti definisi DTDL.

Untuk membuat hubungan, Anda perlu menentukan:

  • ID kembar sumber (srcId dalam sampel kode di bawah): ID kembar tempat hubungan berasal.
  • ID kembar target (targetId dalam sampel kode di bawah): ID kembar tempat hubungan tiba.
  • Nama hubungan (relName dalam sampel kode di bawah): Jenis hubungan generik, sesuatu seperti isi.
  • ID hubungan (relId dalam sampel kode di bawah): nama khusus untuk hubungan ini, sesuatu seperti Hubungan1.

ID hubungan harus unik dalam kembar sumber yang diberikan. Tidak perlu unik secara global. Misalnya, untuk Foo kembar, setiap ID hubungan tertentu harus unik. Namun, Bar kembar lain dapat memiliki hubungan keluar yang cocok dengan ID yang sama dari hubungan Foo.

Contoh kode sampel berikut ini menggambarkan cara membuat hubungan di instans Azure Digital Twins Anda. Ini menggunakan panggilan SDK (disorot) di dalam metode kustom yang mungkin muncul dalam konteks program yang lebih besar.

private async static Task CustomMethod_CreateRelationshipAsync(DigitalTwinsClient client, string srcId, string targetId, string relName, IDictionary<string,object> inputProperties)
{
    var relationship = new BasicRelationship
    {
        TargetId = targetId,
        Name = relName,
        Properties = inputProperties
    };

    try
    {
        string relId = $"{srcId}-{relName}->{targetId}";
        await client.CreateOrReplaceRelationshipAsync<BasicRelationship>(srcId, relId, relationship);
        Console.WriteLine($"Created {relName} relationship successfully. Relationship ID is {relId}.");
    }
    catch (RequestFailedException rex)
    {
        Console.WriteLine($"Create relationship error: {rex.Status}:{rex.Message}");
    }

}

Fungsi kustom ini sekarang dapat dipanggil untuk membuat hubungan berisi dengan cara berikut:

await CustomMethod_CreateRelationshipAsync(client, srcId, targetId, "contains", properties);

Jika Anda ingin membuat beberapa hubungan, Anda dapat mengulangi panggilan ke metode yang sama, meneruskan beberapa jenis hubungan yang berbeda ke dalam argumen.

Untuk informasi selengkapnya tentang kelas pembantu BasicRelationship, lihat API dan SDK Azure Digital Twins.

Membuat beberapa hubungan antara yang kembar

Hubungan dapat diklasifikasikan sebagai:

  • Hubungan keluar: Hubungan milik kembar ini yang menunjuk ke luar untuk menghubungkannya dengan kembar lain. Metode GetRelationshipsAsync() ini digunakan untuk mendapatkan hubungan keluar dari kembar.
  • Hubungan yang masuk: Hubungan milik kembar lain yang menunjuk ke arah kembar ini untuk membuat tautan "masuk". Metode GetIncomingRelationshipsAsync() ini digunakan untuk mendapatkan hubungan masuk dari kembar.

Tidak ada batasan jumlah hubungan yang dapat Anda miliki di antara dua kembar—Anda dapat memiliki sebanyak mungkin hubungan antara kembar yang Anda inginkan.

Fakta ini berarti Bahwa Anda dapat mengekspresikan beberapa jenis hubungan yang berbeda antara dua kembar sekaligus. Misalnya, Kembar A dapat memiliki hubungan yang tersimpan dan hubungan yang diproduksi dengan Kembar B.

Anda bahkan dapat membuat beberapa instans dari jenis hubungan yang sama antara dua kembar yang sama, jika Anda mau. Dalam contoh ini, Kembar A bisa memiliki dua hubungan yang disimpan yang berbeda dengan Twin B, selama kedua hubungan memiliki ID hubungan yang berbeda.

Catatan

Atribut DTDL dan minMultiplicitymaxMultiplicity untuk hubungan saat ini tidak didukung di Azure Digital Twins—bahkan jika didefinisikan sebagai bagian dari model, atribut tersebut tidak akan diberlakukan oleh layanan. Untuk informasi selengkapnya, lihat Catatan DTDL khusus layanan.

Membuat hubungan secara massal dengan Api Pekerjaan Impor

Anda dapat menggunakan API Impor Pekerjaan untuk membuat banyak hubungan sekaligus dalam satu panggilan API. Metode ini memerlukan penggunaan Azure Blob Storage, serta izin tulis di instans Azure Digital Twins Anda untuk hubungan dan pekerjaan massal.

Tip

API Pekerjaan Impor juga memungkinkan model dan kembar diimpor dalam panggilan yang sama, untuk membuat semua bagian grafik sekaligus. Untuk informasi selengkapnya tentang proses ini, lihat Mengunggah model, kembar, dan hubungan secara massal dengan API Impor Pekerjaan.

Untuk mengimpor hubungan secara massal, Anda harus menyusun hubungan Anda (dan sumber daya lain yang disertakan dalam pekerjaan impor massal) sebagai file NDJSON . Bagian ini Relationships muncul setelah bagian Twins , menjadikannya bagian data grafik terakhir dalam file. Hubungan yang ditentukan dalam file dapat mereferensikan kembar yang didefinisikan dalam file ini atau sudah ada dalam instans, dan mereka dapat secara opsional menyertakan inisialisasi properti apa pun yang dimiliki hubungan.

Anda dapat melihat contoh file impor dan proyek sampel untuk membuat file-file ini dalam pengantar Api Pekerjaan Impor.

Selanjutnya, file perlu diunggah ke dalam blob tambahan di Azure Blob Storage. Untuk petunjuk tentang cara membuat kontainer penyimpanan Azure, lihat Membuat kontainer. Kemudian, unggah file menggunakan metode pengunggahan pilihan Anda (beberapa opsi adalah perintah AzCopy, Azure CLI, atau portal Azure).

Setelah file NDJSON diunggah ke kontainer, dapatkan URL-nya dalam kontainer blob. Anda akan menggunakan nilai ini nanti dalam isi panggilan API impor massal.

Berikut adalah cuplikan layar yang menunjukkan nilai URL file blob di portal Azure:

Screenshot of the Azure portal showing the URL of a file in a storage container.

Kemudian, file dapat digunakan dalam panggilan Api Pekerjaan Impor. Anda akan menyediakan URL penyimpanan blob file input, serta URL penyimpanan blob baru untuk menunjukkan di mana Anda ingin log output disimpan saat dibuat oleh layanan.

Mendaftarkan hubungan

Mencantumkan properti dari hubungan tunggal

Anda selalu dapat mendeserialisasi data hubungan ke jenis pilihan Anda. Untuk akses dasar ke hubungan, gunakan jenis BasicRelationship. Kelas BasicRelationship pembantu juga mengizinkan Anda mengakses properti yang ditentukan pada kembar melalui IDictionary<string, object>. Untuk mencantumkan properti, Anda bisa menggunakan:

public async Task ListRelationshipProperties(DigitalTwinsClient client, string twinId, string relId, BasicDigitalTwin twin)
{

    var res = await client.GetRelationshipAsync<BasicRelationship>(twinId, relId);
    BasicRelationship rel = res.Value;
    Console.WriteLine($"Relationship Name: {rel.Name}");
    foreach (string prop in rel.Properties.Keys)
    {
        if (twin.Contents.TryGetValue(prop, out object value))
        {
            Console.WriteLine($"Property '{prop}': {value}");
        }
    }
}

Mencantumkan hubungan keluar dari kembar digital

Untuk mengakses daftar hubungan keluar untuk kembaran tertentu dalam grafik, Anda dapat menggunakan metode GetRelationships() seperti ini:

AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);

Metode ini menampilkan Azure.Pageable<T> atau Azure.AsyncPageable<T>, bergantung pada apakah Anda menggunakan versi panggilan sinkron atau asinkron.

Berikut adalah contoh yang mengambil daftar hubungan. Ini menggunakan panggilan SDK (disorot) di dalam metode kustom yang mungkin muncul dalam konteks program yang lebih besar.

private static async Task<List<BasicRelationship>> CustomMethod_FindOutgoingRelationshipsAsync(DigitalTwinsClient client, string dtId)
{
    // Find the relationships for the twin
    
    try
    {
        // GetRelationshipsAsync will throw if an error occurs
        AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);
        var results = new List<BasicRelationship>();
        await foreach (BasicRelationship rel in rels)
        {
            results.Add(rel);
            Console.WriteLine($"Found relationship: {rel.Id}");

            //Print its properties
            Console.WriteLine($"Relationship properties:");
            foreach(KeyValuePair<string, object> property in rel.Properties)
            {
                Console.WriteLine("{0} = {1}", property.Key, property.Value);
            }
        }

        return results;
    }
    catch (RequestFailedException ex)
    {
        Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving relationships for {dtId} due to {ex.Message}");
        return null;
    }
}

Anda sekarang dapat memanggil metode khusus ini untuk melihat hubungan keluar si kembar seperti ini:

await CustomMethod_FindOutgoingRelationshipsAsync(client, twin_Id);

Anda dapat menggunakan hubungan yang diambil untuk menavigasi ke kembar lain dalam grafik Anda dengan membaca bidang target dari hubungan yang ditampilkan, dan menggunakannya sebagai ID untuk panggilan berikutnya ke GetDigitalTwin().

Mencantumkan hubungan yang masuk ke kembar digital

Azure Digital Twins juga memiliki panggilan SDK untuk menemukan semua hubungan masuk ke kembar tertentu. SDK ini sering berguna untuk navigasi terbalik, atau saat menghapus kembar.

Catatan

IncomingRelationship panggilan tidak mengembalikan seluruh badan hubungan. Untuk informasi selengkapnya tentang kelas IncomingRelationship, lihat dokumentasi referensinya.

Sampel kode di bagian sebelumnya berfokus pada menemukan hubungan keluar dari kembar. Contoh berikut disusun serupa, tetapi menemukan hubungan yang masuk ke kembar sebagai gantinya. Contoh ini menggunakan panggilan SDK (disorot) di dalam metode kustom yang mungkin muncul dalam konteks program yang lebih besar.

private static async Task<List<IncomingRelationship>> CustomMethod_FindIncomingRelationshipsAsync(DigitalTwinsClient client, string dtId)
{
    // Find the relationships for the twin
    
    try
    {
        // GetRelationshipsAsync will throw an error if a problem occurs
        AsyncPageable<IncomingRelationship> incomingRels = client.GetIncomingRelationshipsAsync(dtId);

        var results = new List<IncomingRelationship>();
        await foreach (IncomingRelationship incomingRel in incomingRels)
        {
            results.Add(incomingRel);
            Console.WriteLine($"Found incoming relationship: {incomingRel.RelationshipId}");

            //Print its properties
            Response<BasicRelationship> relResponse = await client.GetRelationshipAsync<BasicRelationship>(incomingRel.SourceId, incomingRel.RelationshipId);
            BasicRelationship rel = relResponse.Value;
            Console.WriteLine($"Relationship properties:");
            foreach(KeyValuePair<string, object> property in rel.Properties)
            {
                Console.WriteLine("{0} = {1}", property.Key, property.Value);
            }
        }
        return results;
    }
    catch (RequestFailedException ex)
    {
        Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving incoming relationships for {dtId} due to {ex.Message}");
        return null;
    }
}

Anda sekarang dapat memanggil metode khusus ini untuk melihat hubungan masuk kembar seperti ini:

await CustomMethod_FindIncomingRelationshipsAsync(client, twin_Id);

Daftar semua properti dan hubungan kembar

Menggunakan metode di atas untuk mencantumkan hubungan keluar dan masuk ke kembaran, Anda dapat membuat metode yang mencetak informasi kembar penuh, termasuk properti kembar dan kedua jenis hubungannya. Berikut adalah contoh metode kustom yang menunjukkan cara menggabungkan metode kustom di atas untuk tujuan ini.

private static async Task CustomMethod_FetchAndPrintTwinAsync(string twin_Id, DigitalTwinsClient client)
{
    Response<BasicDigitalTwin> res = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twin_Id);
    await CustomMethod_FindOutgoingRelationshipsAsync(client, twin_Id);
    await CustomMethod_FindIncomingRelationshipsAsync(client, twin_Id);

    return;
}

Anda sekarang dapat memanggil fungsi kustom ini seperti ini:

await CustomMethod_FetchAndPrintTwinAsync(srcId, client);

Perbarui hubungan

Hubungan diperbarui menggunakan metode UpdateRelationship.

Catatan

Metode ini untuk memperbarui properti hubungan. Jika Anda perlu mengubah kembaran sumber atau kembaran target hubungan, Anda harus menghapus hubungan dan membuat ulang hubungan menggunakan kembar baru.

Parameter yang diperlukan untuk panggilan klien adalah:

  • ID dari kembar sumber (kembar tempat hubungan berasal).
  • ID hubungan yang akan diperbarui.
  • Dokumen Patch JSON yang berisi properti dan nilai baru yang ingin Anda perbarui.

Berikut cuplikan kode sampel yang menunjukkan cara menggunakan metode ini. Ini menggunakan panggilan SDK (disorot) di dalam metode kustom yang mungkin muncul dalam konteks program yang lebih besar.

private async static Task CustomMethod_UpdateRelationshipAsync(DigitalTwinsClient client, string srcId, string relId, Azure.JsonPatchDocument updateDocument)
{

    try
    {
        await client.UpdateRelationshipAsync(srcId, relId, updateDocument);
        Console.WriteLine($"Successfully updated {relId}");
    }
    catch (RequestFailedException rex)
    {
        Console.WriteLine($"Update relationship error: {rex.Status}:{rex.Message}");
    }

}

Berikut adalah contoh panggilan ke metode kustom ini, dengan meneruskan dokumen Patch JSON dengan informasi untuk memperbarui properti.

var updatePropertyPatch = new JsonPatchDocument();
updatePropertyPatch.AppendAdd("/ownershipUser", "ownershipUser NEW value");
await CustomMethod_UpdateRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}", updatePropertyPatch);

Hapus hubungan

Parameter pertama menentukan kembar sumber (kembar tempat hubungan berasal). Parameter lainnya adalah ID hubungan. Anda memerlukan ID kembar dan ID hubungan, karena ID hubungan hanya unik dalam lingkup kembar.

Berikut kode sampel yang menunjukkan cara menggunakan metode ini. Ini menggunakan panggilan SDK (disorot) di dalam metode kustom yang mungkin muncul dalam konteks program yang lebih besar.

private static async Task CustomMethod_DeleteRelationshipAsync(DigitalTwinsClient client, string srcId, string relId)
{
    try
    {
        Response response = await client.DeleteRelationshipAsync(srcId, relId);
        await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
        Console.WriteLine("Deleted relationship successfully");
    }
    catch (RequestFailedException e)
    {
        Console.WriteLine($"Error {e.ErrorCode}");
    }
}

Sekarang Anda dapat memanggil metode kustom ini untuk menghapus hubungan seperti ini:

await CustomMethod_DeleteRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}");

Catatan

Jika Anda ingin menghapus semua model, kembar, dan hubungan dalam instans sekaligus, gunakan Delete Jobs API.

Membuat beberapa elemen grafik sekaligus

Bagian ini menjelaskan strategi untuk membuat grafik dengan beberapa elemen secara bersamaan, daripada menggunakan panggilan API individual untuk mengunggah model, kembar, dan hubungan untuk mengunggahnya satu per satu.

Mengunggah model, kembar, dan hubungan secara massal dengan Api Pekerjaan Impor

Anda dapat menggunakan API Impor Pekerjaan untuk mengunggah beberapa model, kembar, dan hubungan ke instans Anda dalam satu panggilan API, secara efektif membuat grafik sekaligus. Metode ini memerlukan penggunaan Azure Blob Storage, serta izin tulis dalam instans Azure Digital Twins Anda untuk elemen grafik (model, kembar, dan hubungan) dan pekerjaan massal.

Untuk mengimpor sumber daya secara massal, mulailah dengan membuat file NDJSON yang berisi detail sumber daya Anda. File dimulai dengan Header bagian , diikuti oleh bagian Modelsopsional , , Twinsdan Relationships. Anda tidak perlu menyertakan ketiga jenis data grafik dalam file, tetapi bagian apa pun yang ada harus mengikuti urutan tersebut. Kembar yang ditentukan dalam file dapat mereferensikan model yang ditentukan dalam file ini atau sudah ada dalam instans, dan mereka dapat secara opsional menyertakan inisialisasi properti kembar. Hubungan yang ditentukan dalam file dapat mereferensikan kembar yang ditentukan dalam file ini atau sudah ada dalam instans, dan mereka dapat secara opsional menyertakan inisialisasi properti hubungan.

Anda dapat melihat contoh file impor dan proyek sampel untuk membuat file-file ini dalam pengantar Api Pekerjaan Impor.

Selanjutnya, file perlu diunggah ke dalam blob tambahan di Azure Blob Storage. Untuk petunjuk tentang cara membuat kontainer penyimpanan Azure, lihat Membuat kontainer. Kemudian, unggah file menggunakan metode pengunggahan pilihan Anda (beberapa opsi adalah perintah AzCopy, Azure CLI, atau portal Azure).

Setelah file NDJSON diunggah ke kontainer, dapatkan URL-nya dalam kontainer blob. Anda akan menggunakan nilai ini nanti dalam isi panggilan API impor massal.

Berikut adalah cuplikan layar yang menunjukkan nilai URL file blob di portal Azure:

Screenshot of the Azure portal showing the URL of a file in a storage container.

Kemudian, file dapat digunakan dalam panggilan Api Pekerjaan Impor. Anda akan menyediakan URL penyimpanan blob file input, serta URL penyimpanan blob baru untuk menunjukkan di mana Anda ingin log output disimpan saat dibuat oleh layanan.

Mengimpor grafik dengan Azure Digital Twins Explorer

Azure Digital Twins Explorer adalah alat visual untuk melihat dan berinteraksi dengan grafik kembar Anda. Ini berisi fitur untuk mengimpor file grafik dalam format JSON atau Excel yang dapat berisi beberapa model, kembar, dan hubungan.

Untuk informasi mendetail tentang menggunakan fitur ini, lihat Mengimpor grafik dalam dokumentasi Azure Digital Twins Explorer.

Membuat kembar dan hubungan dari file CSV

Terkadang, Anda mungkin perlu membuat hierarki kembar dari data yang disimpan dalam database yang berbeda, atau di spreadsheet atau file CSV. Bagian ini menggambarkan cara membaca data dari file CSV dan membuat grafik kembar darinya.

Pertimbangkan tabel data berikut, yang menjelaskan sekumpulan kembar digital dan hubungan. Model yang dirujuk dalam file ini harus sudah ada di instans Azure Digital Twins.

ID Model ID Kembar (harus unik) Nama hubungan ID kembar target Data awal kembar
dtmi:example:Floor;1 Floor1 mengandung Room1
dtmi:example:Floor;1 Floor0 mengandung Room0
dtmi:example:Room;1 Room1 {"Temperature": 80}
dtmi:example:Room;1 Room0 {"Temperature": 70}

Salah satu cara untuk memasukkan data ini ke Azure Digital Twins adalah dengan mengonversi tabel menjadi file CSV. Setelah tabel dikonversi, kode dapat ditulis untuk menginterpretasikan file ke dalam perintah untuk membuat kembar dan hubungan. Sampel kode berikut mengilustrasikan membaca data dari file CSV dan membuat grafik kembar di Azure Digital Twins.

Dalam kode di bawah ini, file CSV disebut data.csv, dan ada tempat penampung yang mewakili nama host instans Azure Digital Twins Anda. Sampel juga menggunakan beberapa paket yang dapat Anda tambahkan ke proyek Anda untuk membantu proses ini.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Azure;
using Azure.DigitalTwins.Core;
using Azure.Identity;

namespace creating_twin_graph_from_csv
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var relationshipRecordList = new List<BasicRelationship>();
            var twinList = new List<BasicDigitalTwin>();
            List<List<string>> data = ReadData();
            DigitalTwinsClient client = CreateDtClient();

            // Interpret the CSV file data, by each row
            foreach (List<string> row in data)
            {
                string modelID = row.Count > 0 ? row[0].Trim() : null;
                string srcID = row.Count > 1 ? row[1].Trim() : null;
                string relName = row.Count > 2 ? row[2].Trim() : null;
                string targetID = row.Count > 3 ? row[3].Trim() : null;
                string initProperties = row.Count > 4 ? row[4].Trim() : null;
                Console.WriteLine($"ModelID: {modelID}, TwinID: {srcID}, RelName: {relName}, TargetID: {targetID}, InitData: {initProperties}");
                var props = new Dictionary<string, object>();
                // Parse properties into dictionary (left out for compactness)
                // ...

                // Null check for source and target IDs
                if (!string.IsNullOrWhiteSpace(srcID) && !string.IsNullOrWhiteSpace(targetID) && !string.IsNullOrWhiteSpace(relName))
                {
                    relationshipRecordList.Add(
                        new BasicRelationship
                        {
                            SourceId = srcID,
                            TargetId = targetID,
                            Name = relName,
                        });
                }

                if (!string.IsNullOrWhiteSpace(srcID) && !string.IsNullOrWhiteSpace(modelID))
                twinList.Add(
                    new BasicDigitalTwin
                    {
                        Id = srcID,
                        Metadata = { ModelId = modelID },
                        Contents = props,
                    });
            }

            // Create digital twins
            foreach (BasicDigitalTwin twin in twinList)
            {
                try
                {
                    await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twin.Id, twin);
                    Console.WriteLine("Twin is created");
                }
                catch (RequestFailedException ex)
                {
                    Console.WriteLine($"Error {ex.Status}: {ex.Message}");
                }
            }

            // Create relationships between the twins
            foreach (BasicRelationship rec in relationshipRecordList)
            {
                string relId = $"{rec.SourceId}-{rec.Name}->{rec.TargetId}";
                try
                {
                    await client.CreateOrReplaceRelationshipAsync<BasicRelationship>(rec.SourceId, relId, rec);
                    Console.WriteLine($"Relationship {relId} is created");
                }
                catch (RequestFailedException ex)
                {
                    Console.WriteLine($"Error creating relationship {relId}. {ex.Status}: {ex.Message}");
                }
            }
        }

        // Method to ingest data from the CSV file
        public static List<List<string>> ReadData()
        {
            string path = "<path-to>/data.csv";
            string[] lines = System.IO.File.ReadAllLines(path);
            var data = new List<List<string>>();
            int count = 0;
            foreach (string line in lines)
            {
                if (count++ == 0)
                    continue;
                var cols = new List<string>();
                string[] columns = line.Split(',');
                foreach (string column in columns)
                {
                    cols.Add(column);
                }
                data.Add(cols);
            }
            return data;
        }

        // Method to create the digital twins client
        private static DigitalTwinsClient CreateDtClient()
        {
            string adtInstanceUrl = "https://<your-instance-hostname>";
            var credentials = new DefaultAzureCredential();
            return new DigitalTwinsClient(new Uri(adtInstanceUrl), credentials);
        }
    }
}

Sampel grafik kembar yang dapat dijalankan

Cuplikan kode yang dapat dijalankan berikut menggunakan operasi hubungan dari artikel ini untuk membuat grafik kembar dari kembar digital dan hubungan.

Menyiapkan file proyek sampel

Cuplikan menggunakan dua definisi model sampel, Room.json dan Floor.json. Untuk mengunduh file model sehingga Anda dapat menggunakannya dalam kode Anda, gunakan tautan ini untuk langsung masuk ke file di GitHub. Kemudian, klik kanan di mana saja di layar, pilih Simpan sebagai di menu klik kanan browser Anda, dan gunakan jendela Simpan Sebagai untuk menyimpan file sebagai Room.json dan Floor.json.

Selanjutnya, buat proyek aplikasi konsol baru di Visual Studio atau editor pilihan Anda.

Kemudian, salin kode berikut dari sampel yang dapat dijalankan ke dalam proyek Anda:

using System;
using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
using Azure;
using Azure.DigitalTwins.Core;
using Azure.Identity;

namespace DigitalTwins_Samples
{
    public class GraphOperationsSample
    {
        public static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            // Create the Azure Digital Twins client for API calls
            DigitalTwinsClient client = createDtClient();
            Console.WriteLine($"Service client created – ready to go");
            Console.WriteLine();

            // Upload models
            Console.WriteLine($"Upload models");
            Console.WriteLine();
            string dtdl = File.ReadAllText("<path-to>/Room.json");
            string dtdl1 = File.ReadAllText("<path-to>/Floor.json");
            var models = new List<string>
            {
                dtdl,
                dtdl1,
            };
            // Upload the models to the service
            await client.CreateModelsAsync(models);

            // Create new (Floor) digital twin
            var floorTwin = new BasicDigitalTwin();
            string srcId = "myFloorID";
            floorTwin.Metadata.ModelId = "dtmi:example:Floor;1";
            // Floor twins have no properties, so nothing to initialize
            // Create the twin
            await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(srcId, floorTwin);
            Console.WriteLine("Twin created successfully");

            // Create second (Room) digital twin
            var roomTwin = new BasicDigitalTwin();
            string targetId = "myRoomID";
            roomTwin.Metadata.ModelId = "dtmi:example:Room;1";
            // Initialize properties
            roomTwin.Contents.Add("Temperature", 35.0);
            roomTwin.Contents.Add("Humidity", 55.0);
            // Create the twin
            await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(targetId, roomTwin);
            
            // Create relationship between them
            var properties = new Dictionary<string, object>
            {
                { "ownershipUser", "ownershipUser original value" },
            };
            // <UseCreateRelationship>
            await CustomMethod_CreateRelationshipAsync(client, srcId, targetId, "contains", properties);
            // </UseCreateRelationship>
            Console.WriteLine();

            // Update relationship's Name property
            // <UseUpdateRelationship>
            var updatePropertyPatch = new JsonPatchDocument();
            updatePropertyPatch.AppendAdd("/ownershipUser", "ownershipUser NEW value");
            await CustomMethod_UpdateRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}", updatePropertyPatch);
            // </UseUpdateRelationship>
            Console.WriteLine();

            //Print twins and their relationships
            Console.WriteLine("--- Printing details:");
            Console.WriteLine($"Outgoing relationships from source twin, {srcId}:");
            // <UseFetchAndPrint>
            await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
            // </UseFetchAndPrint>
            Console.WriteLine();
            Console.WriteLine($"Incoming relationships to target twin, {targetId}:");
            await CustomMethod_FetchAndPrintTwinAsync(targetId, client);
            Console.WriteLine("--------");
            Console.WriteLine();

            // Delete the relationship
            // <UseDeleteRelationship>
            await CustomMethod_DeleteRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}");
            // </UseDeleteRelationship>
            Console.WriteLine();

            // Print twins and their relationships again
            Console.WriteLine("--- Printing details (after relationship deletion):");
            Console.WriteLine("Outgoing relationships from source twin:");
            await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
            Console.WriteLine();
            Console.WriteLine("Incoming relationships to target twin:");
            await CustomMethod_FetchAndPrintTwinAsync(targetId, client);
            Console.WriteLine("--------");
            Console.WriteLine();
        }

        private static DigitalTwinsClient createDtClient()
        {
            string adtInstanceUrl = "https://<your-instance-hostname>";
            var credentials = new DefaultAzureCredential();
            var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), credentials);
            return client;
        }

        // <CreateRelationshipMethod>
        private async static Task CustomMethod_CreateRelationshipAsync(DigitalTwinsClient client, string srcId, string targetId, string relName, IDictionary<string,object> inputProperties)
        {
            var relationship = new BasicRelationship
            {
                TargetId = targetId,
                Name = relName,
                Properties = inputProperties
            };

            try
            {
                string relId = $"{srcId}-{relName}->{targetId}";
                await client.CreateOrReplaceRelationshipAsync<BasicRelationship>(srcId, relId, relationship);
                Console.WriteLine($"Created {relName} relationship successfully. Relationship ID is {relId}.");
            }
            catch (RequestFailedException rex)
            {
                Console.WriteLine($"Create relationship error: {rex.Status}:{rex.Message}");
            }

        }
        // </CreateRelationshipMethod>

        // <UpdateRelationshipMethod>
        private async static Task CustomMethod_UpdateRelationshipAsync(DigitalTwinsClient client, string srcId, string relId, Azure.JsonPatchDocument updateDocument)
        {

            try
            {
                await client.UpdateRelationshipAsync(srcId, relId, updateDocument);
                Console.WriteLine($"Successfully updated {relId}");
            }
            catch (RequestFailedException rex)
            {
                Console.WriteLine($"Update relationship error: {rex.Status}:{rex.Message}");
            }

        }
        // </UpdateRelationshipMethod>

        // <FetchAndPrintMethod>
        private static async Task CustomMethod_FetchAndPrintTwinAsync(string twin_Id, DigitalTwinsClient client)
        {
            Response<BasicDigitalTwin> res = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twin_Id);
            // <UseFindOutgoingRelationships>
            await CustomMethod_FindOutgoingRelationshipsAsync(client, twin_Id);
            // </UseFindOutgoingRelationships>
            // <UseFindIncomingRelationships>
            await CustomMethod_FindIncomingRelationshipsAsync(client, twin_Id);
            // </UseFindIncomingRelationships>

            return;
        }
        // </FetchAndPrintMethod>

        // <FindOutgoingRelationshipsMethod>
        private static async Task<List<BasicRelationship>> CustomMethod_FindOutgoingRelationshipsAsync(DigitalTwinsClient client, string dtId)
        {
            // Find the relationships for the twin
            
            try
            {
                // GetRelationshipsAsync will throw if an error occurs
                // <GetRelationshipsCall>
                AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);
                // </GetRelationshipsCall>
                var results = new List<BasicRelationship>();
                await foreach (BasicRelationship rel in rels)
                {
                    results.Add(rel);
                    Console.WriteLine($"Found relationship: {rel.Id}");

                    //Print its properties
                    Console.WriteLine($"Relationship properties:");
                    foreach(KeyValuePair<string, object> property in rel.Properties)
                    {
                        Console.WriteLine("{0} = {1}", property.Key, property.Value);
                    }
                }

                return results;
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving relationships for {dtId} due to {ex.Message}");
                return null;
            }
        }
        // </FindOutgoingRelationshipsMethod>

        // <FindIncomingRelationshipsMethod>
        private static async Task<List<IncomingRelationship>> CustomMethod_FindIncomingRelationshipsAsync(DigitalTwinsClient client, string dtId)
        {
            // Find the relationships for the twin
            
            try
            {
                // GetRelationshipsAsync will throw an error if a problem occurs
                AsyncPageable<IncomingRelationship> incomingRels = client.GetIncomingRelationshipsAsync(dtId);

                var results = new List<IncomingRelationship>();
                await foreach (IncomingRelationship incomingRel in incomingRels)
                {
                    results.Add(incomingRel);
                    Console.WriteLine($"Found incoming relationship: {incomingRel.RelationshipId}");

                    //Print its properties
                    Response<BasicRelationship> relResponse = await client.GetRelationshipAsync<BasicRelationship>(incomingRel.SourceId, incomingRel.RelationshipId);
                    BasicRelationship rel = relResponse.Value;
                    Console.WriteLine($"Relationship properties:");
                    foreach(KeyValuePair<string, object> property in rel.Properties)
                    {
                        Console.WriteLine("{0} = {1}", property.Key, property.Value);
                    }
                }
                return results;
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving incoming relationships for {dtId} due to {ex.Message}");
                return null;
            }
        }
        // </FindIncomingRelationshipsMethod>

        // <DeleteRelationshipMethod>
        private static async Task CustomMethod_DeleteRelationshipAsync(DigitalTwinsClient client, string srcId, string relId)
        {
            try
            {
                Response response = await client.DeleteRelationshipAsync(srcId, relId);
                await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
                Console.WriteLine("Deleted relationship successfully");
            }
            catch (RequestFailedException e)
            {
                Console.WriteLine($"Error {e.ErrorCode}");
            }
        }
        // </DeleteRelationshipMethod>
    }
}

Catatan

Saat ini ada masalah yang diketahui yang memengaruhi DefaultAzureCredential kelas pembungkus yang dapat mengakibatkan kesalahan saat mengautentikasi. Jika Anda mengalami masalah ini, Anda dapat mencoba membuat instans DefaultAzureCredential dengan parameter opsional berikut untuk mengatasinya: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });

Untuk informasi selengkapnya tentang masalah ini, lihat Masalah umum Azure Digital Twins.

Mengonfigurasi proyek

Selanjutnya, selesaikan langkah-langkah berikut untuk mengonfigurasi kode proyek Anda:

  1. Tambahkan Room.json dan file Floor.jons yang Anda unduh sebelumnya ke proyek Anda, dan ganti <path-to> tempat penampung dalam kode untuk memberi tahu program Anda tempat untuk menemukannya.

  2. Ganti tempat penampung <your-instance-hostname> dengan nama host instans Azure Digital Twins Anda.

  3. Tambahkan dua dependensi ke proyek Anda yang akan diperlukan untuk bekerja dengan Azure Digital Twins. Yang pertama adalah paket untuk SDK Azure Digital Twins untuk .NET, dan yang kedua menyediakan alat untuk membantu autentikasi terhadap Azure.

    dotnet add package Azure.DigitalTwins.Core
    dotnet add package Azure.Identity
    

Anda juga harus menyiapkan info masuk lokal jika ingin menjalankan sampel secara langsung. Bagian selanjutnya berjalan melalui proses ini.

Siapkan kredensial Azure lokal

Sampel ini menggunakan DefaultAzureCredential (bagian dari pustaka Azure.Identity) untuk mengautentikasi pengguna dengan instans Azure Digital Twins saat Anda menjalankannya di komputer lokal Anda. Untuk informasi selengkapnya tentang berbagai cara aplikasi klien dapat mengautentikasi dengan Azure Digital Twins, lihat Menulis kode autentikasi aplikasi.

Dengan DefaultAzureCredential, sampel akan mencari kredensial di lingkungan lokal Anda, seperti masuk Azure di Azure CLI lokal atau di Visual Studio atau Visual Studio Code. Untuk alasan ini, Anda harus masuk ke Azure secara lokal melalui salah satu mekanisme ini untuk menyiapkan kredensial untuk sampel tersebut.

Jika Anda menggunakan Visual Studio atau Visual Studio Code untuk menjalankan sampel kode, pastikan Anda masuk ke editor tersebut dengan kredensial Azure yang sama dengan yang ingin Anda gunakan untuk mengakses instans Azure Digital Twins Anda. Jika Anda menggunakan jendela CLI lokal, jalankan az login perintah untuk masuk ke akun Azure Anda. Setelah ini, saat menjalankan sampel kode, Anda harus diautentikasi secara otomatis.

Jalankan sampel

Sekarang setelah menyelesaikan persiapan, Anda dapat menjalankan proyek kode sampel.

Berikut adalah output konsol dari program:

Screenshot of the console output showing the twin details with incoming and outgoing relationships of the twins.

Tip

Grafik kembar adalah konsep menciptakan hubungan antara kembar. Jika Anda ingin menampilkan representasi visual grafik kembar, lihat bagian Visualisasi di artikel ini.

Langkah berikutnya

Pelajari tentang mengkueri grafik kembar Azure Digital Twins: