Správa grafu digitálních dvojčat pomocí relací

Jádrem služby Azure Digital Twins je graf dvojčat představující celé prostředí. Graf dvojčat je tvořen jednotlivými digitálními dvojčaty propojenými prostřednictvím relací. Tento článek se zaměřuje na správu vztahů a grafu jako celku; pokud chcete pracovat s jednotlivými digitálními dvojčaty, přečtěte si téma Správa digitálních dvojčat.

Jakmile budete mít funkční instanci Služby Azure Digital Twins a nastavíte ověřovací kód v klientské aplikaci, můžete vytvářet, upravovat a odstraňovat digitální dvojčata a jejich vztahy v instanci Azure Digital Twins.

Požadavky

Pokud chcete pracovat se službou Azure Digital Twins v tomto článku, budete potřebovat instanci služby Azure Digital Twins a požadovaná oprávnění k jeho použití. Pokud už máte nastavenou instanci Služby Azure Digital Twins, můžete tuto instanci použít a přeskočit k další části. V opačném případě postupujte podle pokynů v části Nastavení instance a ověřování. Pokyny obsahují informace, které vám pomůžou ověřit, že jste každý krok úspěšně dokončili.

Po nastavení instance si poznamenejte název hostitele instance. Název hostitele najdete na webu Azure Portal.

Vývojářská rozhraní

Tento článek popisuje, jak provádět různé operace správy pomocí sady .NET (C#) SDK. Stejná volání správy můžete také vytvořit pomocí jiných jazykových sad SDK popsaných v rozhraních API a sadách SDK služby Azure Digital Twins.

Mezi další vývojářská rozhraní, která lze použít k dokončení těchto operací, patří:

Vizualizace

Azure Digital Twins Explorer je vizuální nástroj pro zkoumání dat v grafu Služby Azure Digital Twins. Průzkumníka můžete použít k zobrazení, dotazování a úpravám modelů, dvojčat a relací.

Další informace o nástroji Azure Digital Twins Explorer najdete v Průzkumníku služby Azure Digital Twins. Podrobný postup použití jeho funkcí najdete v tématu Použití Průzkumníka služby Azure Digital Twins.

Vizualizace vypadá takto:

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

Vytvoření vztahů

Vztahy popisují, jak jsou různá digitální dvojčata vzájemně propojená, což tvoří základ grafu dvojčete.

Typy relací, které lze vytvořit z jednoho (zdrojového) dvojčete do jiného (cílového) dvojčete, jsou definovány jako součást modelu DTDL zdrojového dvojčete. Instanci relace můžete vytvořit pomocí CreateOrReplaceRelationshipAsync() volání sady SDK s dvojčaty a podrobnostmi relace, které následují za definicí DTDL.

Pokud chcete vytvořit relaci, musíte zadat:

  • ID zdrojového dvojčete (srcId v ukázce kódu níže): ID dvojčete, odkud relace pochází.
  • ID cílového dvojčete (targetId v ukázce kódu níže): ID dvojčete, do kterého relace dorazí.
  • Název relace (relName v ukázce kódu níže): Obecný typ relace, například obsahuje.
  • ID relace (relId v ukázce kódu níže): Konkrétní název této relace, například Relationship1.

ID relace musí být jedinečné v rámci daného zdrojového dvojčete. Nemusí být globálně jedinečný. Například pro dvojčete Foo musí být každé konkrétní ID relace jedinečné. Jiný pruh dvojčete ale může mít odchozí relaci, která odpovídá stejnému ID relace Foo.

Následující ukázka kódu ukazuje, jak vytvořit relaci v instanci Služby Azure Digital Twins. Používá volání sady SDK (zvýrazněné) uvnitř vlastní metody, která se může objevit v kontextu většího programu.

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

}

Tuto vlastní funkci teď můžete volat k vytvoření relace obsahující relace následujícím způsobem:

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

Pokud chcete vytvořit více relací, můžete opakovat volání stejné metody a předat do argumentu různé typy relací.

Další informace o pomocné třídě BasicRelationshipnajdete v tématu Rozhraní API a sady SDK služby Azure Digital Twins.

Vytvoření více relací mezi dvojčaty

Relace je možné klasifikovat jako jednu z těchto:

  • Odchozí relace: Relace patřící tomuto dvojčeti, které odkazují ven, aby je připojily k jiným dvojčatům. Metoda GetRelationshipsAsync() slouží k získání odchozích relací dvojčete.
  • Příchozí relace: Relace patřící jiným dvojčatům, která odkazují na toto dvojče, vytvoří příchozí propojení. Metoda GetIncomingRelationshipsAsync() slouží k získání příchozích relací dvojčete.

Počet relací, které můžete mít mezi dvěma dvojčaty, neexistuje žádné omezení – můžete mít tolik relací mezi dvojčaty, kolik chcete.

To znamená, že můžete vyjádřit několik různých typů vztahů mezi dvěma dvojčaty najednou. Dvojče A může mít například uloženou relaci i vztah výroby s dvojčetem B.

Pokud chcete, můžete dokonce vytvořit více instancí stejného typu relace mezi stejnými dvěma dvojčaty. V tomto příkladu by dvojče A mohlo mít dvě různé uložené relace s dvojčeteM B, pokud mají relace různá ID relací.

Poznámka:

Atributy minMultiplicity DTDL a maxMultiplicity pro relace se v současné době ve službě Azure Digital Twins nepodporují – i když jsou definované jako součást modelu, služba je nevynucuje. Další informace najdete v poznámkách DTDL specifických pro službu.

Hromadné vytváření relací pomocí rozhraní API pro import úloh

Rozhraní API pro import úloh můžete použít k vytvoření mnoha relací najednou v jednom volání rozhraní API. Tato metoda vyžaduje použití služby Azure Blob Storage a také oprávnění k zápisu v instanci služby Azure Digital Twins pro relace a hromadné úlohy.

Tip

Rozhraní API pro úlohy importu také umožňuje importovat modely a dvojčata ve stejném volání, aby se vytvořily všechny části grafu najednou. Další informace o tomto procesu najdete v tématu Hromadné nahrávání modelů, dvojčat a relací pomocí rozhraní API importu úloh.

Pokud chcete relace importovat hromadně, musíte relace strukturovat (a všechny ostatní prostředky zahrnuté v úloze hromadného importu) jako soubor NDJSON . Oddíl Relationships následuje za Twins oddílem, takže se jedná o poslední datový oddíl grafu v souboru. Relace definované v souboru mohou odkazovat na dvojčata, která jsou definována v tomto souboru nebo již existují v instanci, a mohou volitelně zahrnovat inicializaci všech vlastností, které mají relace.

Ukázkový soubor importu a ukázkový projekt pro vytvoření těchto souborů si můžete prohlédnout v úvodu k rozhraní API importu úloh.

Dále je potřeba soubor nahrát do doplňovacího objektu blob ve službě Azure Blob Storage. Pokyny k vytvoření kontejneru úložiště Azure najdete v tématu Vytvoření kontejneru. Pak soubor nahrajte pomocí preferované metody nahrání (některé možnosti jsou příkaz AzCopy, Azure CLI nebo Azure Portal).

Jakmile se soubor NDJSON nahraje do kontejneru, získejte jeho adresu URL v kontejneru objektů blob. Tuto hodnotu použijete později v textu volání rozhraní API hromadného importu.

Tady je snímek obrazovky znázorňující hodnotu adresy URL souboru objektu blob na webu Azure Portal:

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

Pak se soubor dá použít ve volání rozhraní API importu úloh. Zadáte adresu URL úložiště objektů blob vstupního souboru a také novou adresu URL úložiště objektů blob, která bude indikovat, kam se má výstupní protokol uložit, když služba vytvoří.

Výpis relací

Výpis vlastností jedné relace

Data relací můžete vždy deserializovat na typ podle vašeho výběru. Pro základní přístup k relaci použijte typ BasicRelationship. Pomocná BasicRelationship třída také poskytuje přístup k vlastnostem definovaným v relaci prostřednictvím .IDictionary<string, object> K výpisu vlastností můžete použít:

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

Výpis odchozích relací z digitálního dvojčete

Pro přístup k seznamu odchozích relací pro dané dvojčete v grafu můžete použít metodu GetRelationships() takto:

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

Tato metoda vrátí nebo Azure.Pageable<T>Azure.AsyncPageable<T>, v závislosti na tom, zda používáte synchronní nebo asynchronní verzi volání.

Tady je příklad, který načte seznam relací. Používá volání sady SDK (zvýrazněné) uvnitř vlastní metody, která se může objevit v kontextu většího programu.

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

Teď můžete volat tuto vlastní metodu, abyste viděli odchozí vztahy dvojčat takto:

await CustomMethod_FindOutgoingRelationshipsAsync(client, twin_Id);

Načtené relace můžete použít k přechodu na další dvojčata v grafu tak, že přečtete target pole z vrácené relace a použijete ho jako ID pro vaše další volání GetDigitalTwin().

Výpis příchozích relací k digitálnímu dvojčeti

Azure Digital Twins má také volání sady SDK pro vyhledání všech příchozích relací k danému dvojčeti. Tato sada SDK je často užitečná pro zpětnou navigaci nebo při odstraňování dvojčete.

Poznámka:

IncomingRelationship Volání nevrací celé tělo relace. Další informace o IncomingRelationship třídě najdete v referenční dokumentaci.

Ukázka kódu v předchozí části se zaměřila na vyhledání odchozích relací z dvojčete. Následující příklad je strukturován podobně, ale najde příchozí relace k dvojčeti. Tento příklad také používá volání sady SDK (zvýrazněné) uvnitř vlastní metody, která se může objevit v kontextu většího programu.

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

Teď můžete volat tuto vlastní metodu, abyste viděli příchozí relace dvojčat takto:

await CustomMethod_FindIncomingRelationshipsAsync(client, twin_Id);

Výpis všech vlastností a relací dvojčat

Pomocí výše uvedených metod pro výpis odchozích a příchozích relací do dvojčete můžete vytvořit metodu, která vytiskne informace o úplném dvojčeti, včetně vlastností dvojčete a obou typů vztahů. Tady je příklad vlastní metody ukazující, jak zkombinovat výše uvedené vlastní metody pro tento účel.

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

Teď můžete tuto vlastní funkci volat takto:

await CustomMethod_FetchAndPrintTwinAsync(srcId, client);

Aktualizace relací

Relace se aktualizují pomocí UpdateRelationship metody.

Poznámka:

Tato metoda slouží k aktualizaci vlastností relace. Pokud potřebujete změnit zdrojové dvojče nebo cílové dvojče relace, budete muset relaci odstranit a znovu vytvořit pomocí nových dvojčat.

Požadované parametry pro volání klienta jsou:

  • ID zdrojového dvojčete (dvojče, kde relace pochází).
  • ID relace, která se má aktualizovat.
  • Dokument opravy JSON obsahující vlastnosti a nové hodnoty, které chcete aktualizovat.

Tady je ukázkový fragment kódu, který ukazuje, jak tuto metodu použít. Tento příklad používá volání sady SDK (zvýrazněné) uvnitř vlastní metody, která se může objevit v kontextu většího programu.

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

}

Tady je příklad volání této vlastní metody a předání dokumentu JSON Patch s informacemi o aktualizaci vlastnosti.

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

Odstranění vztahů

První parametr určuje zdrojové dvojče (dvojče, kde relace pochází). Druhým parametrem je ID relace. Potřebujete ID dvojčete i ID relace, protože ID relací jsou jedinečná pouze v rámci oboru dvojčete.

Tady je ukázkový kód, který ukazuje, jak tuto metodu používat. Tento příklad používá volání sady SDK (zvýrazněné) uvnitř vlastní metody, která se může objevit v kontextu většího programu.

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

Teď můžete volat tuto vlastní metodu, která odstraní relaci takto:

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

Poznámka:

Pokud chcete odstranit všechny modely, dvojčata a relace v instanci najednou, použijte rozhraní API pro odstranění úloh.

Vytvoření více prvků grafu najednou

Tato část popisuje strategie pro vytvoření grafu s více prvky najednou místo použití jednotlivých volání rozhraní API k nahrání modelů, dvojčat a relací k jejich nahrání po druhém.

Hromadné nahrávání modelů, dvojčat a relací pomocí rozhraní API pro import úloh

Rozhraní API pro import úloh můžete použít k nahrání více modelů, dvojčat a relací do instance v jediném volání rozhraní API a efektivně tak vytvořit graf najednou. Tato metoda vyžaduje použití služby Azure Blob Storage a také oprávnění k zápisu v instanci služby Azure Digital Twins pro prvky grafu (modely, dvojčata a relace) a hromadné úlohy.

Pokud chcete prostředky importovat hromadně, začněte vytvořením souboru NDJSON obsahujícího podrobnosti o vašich prostředcích. Soubor začíná oddílem Header následovaným volitelnými oddíly Models, Twinsa Relationships. Do souboru nemusíte zahrnout všechny tři typy dat grafu, ale všechny oddíly, které jsou k dispozici, musí postupovat podle tohoto pořadí. Dvojčata definovaná v souboru mohou odkazovat na modely, které jsou definovány buď v tomto souboru, nebo již existují v instanci, a mohou volitelně zahrnovat inicializaci vlastností dvojčete. Relace definované v souboru mohou odkazovat na dvojčata, která jsou definována buď v tomto souboru, nebo již existují v instanci, a mohou volitelně zahrnovat inicializaci vlastností relace.

Ukázkový soubor importu a ukázkový projekt pro vytvoření těchto souborů si můžete prohlédnout v úvodu k rozhraní API importu úloh.

Dále je potřeba soubor nahrát do doplňovacího objektu blob ve službě Azure Blob Storage. Pokyny k vytvoření kontejneru úložiště Azure najdete v tématu Vytvoření kontejneru. Pak soubor nahrajte pomocí preferované metody nahrání (některé možnosti jsou příkaz AzCopy, Azure CLI nebo Azure Portal).

Jakmile se soubor NDJSON nahraje do kontejneru, získejte jeho adresu URL v kontejneru objektů blob. Tuto hodnotu použijete později v textu volání rozhraní API hromadného importu.

Tady je snímek obrazovky znázorňující hodnotu adresy URL souboru objektu blob na webu Azure Portal:

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

Pak se soubor dá použít ve volání rozhraní API importu úloh. Zadáte adresu URL úložiště objektů blob vstupního souboru a také novou adresu URL úložiště objektů blob, která bude indikovat, kam se má výstupní protokol uložit, když služba vytvoří.

Import grafu pomocí Azure Digital Twins Exploreru

Azure Digital Twins Explorer je vizuální nástroj pro zobrazení a interakci s grafem dvojčete. Obsahuje funkci pro import souboru grafu ve formátu JSON nebo Excelu, který může obsahovat více modelů, dvojčat a relací.

Podrobné informace o použití této funkce najdete v tématu Import grafu v dokumentaci k Průzkumníku služby Azure Digital Twins.

Vytvoření dvojčat a relací ze souboru CSV

Někdy může být potřeba vytvořit hierarchie dvojčat z dat uložených v jiné databázi nebo v tabulce nebo v souboru CSV. Tato část ukazuje, jak číst data ze souboru CSV a vytvořit z něj graf dvojčete.

Podívejte se na následující tabulku dat popisující sadu digitálních dvojčat a relací. Modely odkazované v tomto souboru už musí existovat v instanci Azure Digital Twins.

ID modelu ID dvojčete (musí být jedinečné) Název relace ID cílového dvojčete Data inicializačního dvojčete
dtmi:example:Floor; 1 Podlaha 1 obsahuje Pokoj 1
dtmi:example:Floor; 1 Floor0 obsahuje Pokoj 0
dtmi:example:Room; 1 Pokoj 1 {"Teplota": 80}
dtmi:example:Room; 1 Pokoj 0 {"Teplota": 70}

Jedním ze způsobů, jak tato data získat do služby Azure Digital Twins, je převést tabulku na soubor CSV. Po převodu tabulky lze kód zapsat tak, aby soubor interpretoval na příkazy pro vytvoření dvojčat a relací. Následující ukázka kódu ukazuje čtení dat ze souboru CSV a vytvoření grafu dvojčete ve službě Azure Digital Twins.

V následujícím kódu se soubor CSV nazývá data.csv a zástupný symbol představující název hostitele vaší instance Azure Digital Twins. Ukázka také využívá několik balíčků, které můžete přidat do projektu, aby vám s tímto procesem pomohlo.

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

Ukázka grafu spustitelného dvojčete

Následující spustitelný fragment kódu používá operace relací z tohoto článku k vytvoření grafu dvojčete z digitálních dvojčat a relací.

Nastavení ukázkových souborů projektu

Fragment kódu používá dvě ukázkové definice modelu, Room.json a Floor.json. Pokud chcete stáhnout soubory modelu, abyste je mohli použít ve svém kódu, použijte tyto odkazy a přejděte přímo k souborům na GitHubu. Potom klikněte pravým tlačítkem na libovolné místo na obrazovce, v nabídce pravého kliknutí v prohlížeči vyberte Uložit jako a pomocí okna Uložit jako soubory uložte soubory jako Room.json a Floor.json.

Dále vytvořte nový projekt konzolové aplikace v sadě Visual Studio nebo v libovolném editoru.

Pak do projektu zkopírujte následující kód spustitelné ukázky:

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

Poznámka:

V současné době existuje známý problém ovlivňující DefaultAzureCredential třídu obálky, která může způsobit chybu při ověřování. Pokud narazíte na tento problém, můžete zkusit vytvořit instanci DefaultAzureCredential s následujícím volitelným parametrem a vyřešit ho: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });

Další informace o tomto problému najdete v tématu Známé problémy služby Azure Digital Twins.

Konfigurace projektu

Dále proveďte následující kroky a nakonfigurujte kód projektu:

  1. Přidejte soubory Room.json a Floor.json, které jste si stáhli dříve do projektu, a nahraďte <path-to> zástupné symboly v kódu, abyste aplikaci řekli, kde je najdete.

  2. Zástupný symbol <your-instance-hostname> nahraďte názvem hostitele instance Azure Digital Twins.

  3. Přidejte do projektu dvě závislosti, které budou potřeba pro práci se službou Azure Digital Twins. První je balíček sady Azure Digital Twins SDK pro .NET a druhý poskytuje nástroje, které vám pomůžou s ověřováním v Azure.

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

Pokud chcete ukázku spustit přímo, musíte také nastavit místní přihlašovací údaje. Následující část vás provede tímto procesem.

Nastavení místních přihlašovacích údajů Azure

Tato ukázka používá defaultAzureCredential (součást Azure.Identity knihovny) k ověřování uživatelů s instancí Služby Azure Digital Twins, když ji spustíte na místním počítači. Další informace o různých způsobech ověřování klientské aplikace pomocí služby Azure Digital Twins najdete v tématu Psaní ověřovacího kódu aplikace.

Pomocí DefaultAzureCredentialtéto ukázky vyhledáte přihlašovací údaje ve vašem místním prostředí, jako je přihlášení k Azure v místním Azure CLI nebo v sadě Visual Studio nebo Visual Studio Code. Z tohoto důvodu byste se měli k Azure přihlásit místně prostřednictvím jednoho z těchto mechanismů, abyste pro ukázku nastavili přihlašovací údaje.

Pokud ke spouštění ukázek kódu používáte Visual Studio nebo Visual Studio Code, ujistěte se, že jste k ho editoru přihlášeni pomocí stejných přihlašovacích údajů Azure, které chcete použít pro přístup k vaší instanci Azure Digital Twins. Pokud používáte místní okno rozhraní příkazového řádku, spusťte az login příkaz pro přihlášení ke svému účtu Azure. Potom byste při spuštění ukázky kódu měli být automaticky ověřeni.

Spuštění ukázky

Teď, když jste dokončili nastavení, můžete spustit ukázkový projekt kódu.

Tady je výstup konzoly programu:

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

Tip

Graf dvojčat je koncept vytváření vztahů mezi dvojčaty. Pokud chcete zobrazit vizuální znázornění grafu dvojčete, přečtěte si část Vizualizace tohoto článku.

Další kroky

Další informace o dotazování grafu dvojčat Azure Digital Twins: