Dela via


Hantera ett diagram över digitala tvillingar med hjälp av relationer

Kärnan i Azure Digital Twins är tvillingdiagrammet som representerar hela din miljö. Tvillingdiagrammet består av enskilda digitala tvillingar som är anslutna via relationer. Den här artikeln fokuserar på att hantera relationer och grafen som helhet. information om hur du arbetar med enskilda digitala tvillingar finns i Hantera digitala tvillingar.

När du har en fungerande Azure Digital Twins-instans och har konfigurerat autentiseringskod i klientappen kan du skapa, ändra och ta bort digitala tvillingar och deras relationer i en Azure Digital Twins-instans.

Förutsättningar

För att arbeta med Azure Digital Twins i den här artikeln behöver du en Azure Digital Twins-instans och de behörigheter som krävs för att använda den. Om du redan har konfigurerat en Azure Digital Twins-instans kan du använda den instansen och gå vidare till nästa avsnitt. Annars följer du anvisningarna i Konfigurera en instans och autentisering. Anvisningarna innehåller information som hjälper dig att kontrollera att du har slutfört varje steg.

När du har konfigurerat instansen antecknar du instansens värdnamn. Du hittar värdnamnet i Azure-portalen.

Utvecklargränssnitt

Den här artikeln beskriver hur du slutför olika hanteringsåtgärder med hjälp av .NET (C#) SDK. Du kan också skapa samma hanteringsanrop med de andra språk-SDK:erna som beskrivs i Azure Digital Twins-API:er och SDK:er.

Andra utvecklargränssnitt som kan användas för att slutföra dessa åtgärder är:

Visualisering

Azure Digital Twins Explorer är ett visuellt verktyg för att utforska data i ditt Azure Digital Twins-diagram. Du kan använda utforskaren för att visa, fråga och redigera dina modeller, tvillingar och relationer.

Mer information om Azure Digital Twins Explorer-verktyget finns i Azure Digital Twins Explorer. Detaljerade anvisningar om hur du använder dess funktioner finns i Använda Azure Digital Twins Explorer.

Så här ser visualiseringen ut:

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

Skapa relationer

Relationer beskriver hur olika digitala tvillingar är anslutna till varandra, vilket utgör grunden för tvillingdiagrammet.

De typer av relationer som kan skapas från en (käll)tvilling till en annan (mål)-tvilling definieras som en del av källtvillingens DTDL-modell. Du kan skapa en instans av en relation med hjälp av SDK-anropet CreateOrReplaceRelationshipAsync() med tvillingar och relationsinformation som följer DTDL-definitionen.

Om du vill skapa en relation måste du ange:

  • Källtvillingens ID (srcId i kodexemplet nedan): ID:t för tvillingen där relationen kommer.
  • Måltvillingens ID (targetId i kodexemplet nedan): ID:t för tvillingen där relationen kommer.
  • Ett relationsnamn (relName i kodexemplet nedan): Den allmänna typen av relation, ungefär som innehåller.
  • Ett relations-ID (relId i kodexemplet nedan): Det specifika namnet på den här relationen, ungefär som Relation1.

Relations-ID:t måste vara unikt inom den angivna källtvillingen. Den behöver inte vara globalt unik. För tvillingen Foo måste till exempel varje specifikt relations-ID vara unikt. En annan tvillingstapel kan dock ha en utgående relation som matchar samma ID för en Foo-relation.

Följande kodexempel visar hur du skapar en relation i din Azure Digital Twins-instans. Den använder SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.

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

}

Den här anpassade funktionen kan nu anropas för att skapa en contains-relation på följande sätt:

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

Om du vill skapa flera relationer kan du upprepa anrop till samma metod och skicka olika relationstyper till argumentet.

Mer information om hjälpklassen BasicRelationshipfinns i Azure Digital Twins API:er och SDK:er.

Skapa flera relationer mellan tvillingar

Relationer kan klassificeras som antingen:

  • Utgående relationer: Relationer som tillhör den här tvillingen som pekar utåt för att ansluta den till andra tvillingar. Metoden GetRelationshipsAsync() används för att hämta utgående relationer för en tvilling.
  • Inkommande relationer: Relationer som tillhör andra tvillingar som pekar mot den här tvillingen för att skapa en "inkommande" länk. Metoden GetIncomingRelationshipsAsync() används för att hämta inkommande relationer för en tvilling.

Det finns ingen begränsning för antalet relationer som du kan ha mellan två tvillingar – du kan ha så många relationer mellan tvillingar som du vill.

Det innebär att du kan uttrycka flera olika typer av relationer mellan två tvillingar samtidigt. Tvilling A kan till exempel ha både en lagrad relation och en tillverkad relation med Tvilling B.

Du kan till och med skapa flera instanser av samma typ av relation mellan samma två tvillingar, om du vill. I det här exemplet kan Tvilling A ha två olika lagrade relationer med Tvilling B, så länge relationerna har olika relations-ID:n.

Kommentar

DTDL-attributen minMultiplicity för och maxMultiplicity för relationer stöds för närvarande inte i Azure Digital Twins – även om de definieras som en del av en modell tillämpas de inte av tjänsten. Mer information finns i Tjänstspecifika DTDL-anteckningar.

Skapa relationer i grupp med API:et Importera jobb

Du kan använda API:et Importera jobb för att skapa många relationer samtidigt i ett enda API-anrop. Den här metoden kräver användning av Azure Blob Storage, samt skrivbehörigheter i din Azure Digital Twins-instans för relationer och massjobb.

Dricks

MED API:et Importera jobb kan även modeller och tvillingar importeras i samma anrop för att skapa alla delar av ett diagram samtidigt. Mer information om den här processen finns i Ladda upp modeller, tvillingar och relationer i bulk med API:et Importera jobb.

Om du vill importera relationer i grupp måste du strukturera dina relationer (och andra resurser som ingår i massimportjobbet) som en NDJSON-fil . Avsnittet Relationships kommer efter avsnittet Twins , vilket gör det till det sista grafdataavsnittet i filen. Relationer som definierats i filen kan referera till tvillingar som antingen definieras i den här filen eller som redan finns i instansen, och de kan också inkludera initiering av alla egenskaper som relationerna har.

Du kan visa en exempelimportfil och ett exempelprojekt för att skapa dessa filer i introduktionen för API:et Importera jobb.

Därefter måste filen laddas upp till en tilläggsblob i Azure Blob Storage. Anvisningar om hur du skapar en Azure Storage-container finns i Skapa en container. Ladda sedan upp filen med den uppladdningsmetod du föredrar (vissa alternativ är Kommandot AzCopy, Azure CLI eller Azure-portalen).

När NDJSON-filen har laddats upp till containern hämtar du dess URL i blobcontainern. Du använder det här värdet senare i brödtexten i API-anropet för massimport.

Här är en skärmbild som visar URL-värdet för en blobfil i Azure-portalen:

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

Sedan kan filen användas i ett API-anrop för importjobb. Du anger bloblagrings-URL:en för indatafilen samt en ny bloblagrings-URL för att ange var du vill att utdataloggen ska lagras när den skapas av tjänsten.

Lista relationer

Lista egenskaper för en enskild relation

Du kan alltid deserialisera relationsdata till valfri typ. För grundläggande åtkomst till en relation använder du typen BasicRelationship. Hjälpklassen BasicRelationship ger dig också åtkomst till egenskaper som definierats för relationen via en IDictionary<string, object>. Om du vill visa en lista över egenskaper kan du använda:

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

Lista utgående relationer från en digital tvilling

Om du vill komma åt listan över utgående relationer för en viss tvilling i diagrammet kan du använda metoden GetRelationships() så här:

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

Den här metoden returnerar en Azure.Pageable<T> eller Azure.AsyncPageable<T>, beroende på om du använder den synkrona eller asynkrona versionen av anropet.

Här är ett exempel som hämtar en lista över relationer. Den använder SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.

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

Du kan nu anropa den här anpassade metoden för att se tvillingarnas utgående relationer så här:

await CustomMethod_FindOutgoingRelationshipsAsync(client, twin_Id);

Du kan använda de hämtade relationerna för att navigera till andra tvillingar i diagrammet genom att läsa target fältet från relationen som returneras och använda det som ID för nästa anrop till GetDigitalTwin().

Lista inkommande relationer till en digital tvilling

Azure Digital Twins har också ett SDK-anrop för att hitta alla inkommande relationer till en viss tvilling. Denna SDK är ofta användbar för omvänd navigering eller när du tar bort en tvilling.

Kommentar

IncomingRelationship anrop returnerar inte hela brödtexten i relationen. Mer information om klassen finns i referensdokumentationen IncomingRelationship .

Kodexemplet i föregående avsnitt fokuserade på att hitta utgående relationer från en tvilling. Följande exempel är strukturerat på liknande sätt, men hittar inkommande relationer till tvillingen i stället. I det här exemplet används även SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.

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

Du kan nu anropa den här anpassade metoden för att se tvillingarnas inkommande relationer så här:

await CustomMethod_FindIncomingRelationshipsAsync(client, twin_Id);

Visa en lista över alla tvillingegenskaper och relationer

Med hjälp av ovanstående metoder för att lista utgående och inkommande relationer till en tvilling kan du skapa en metod som skriver ut fullständig tvillinginformation, inklusive tvillingens egenskaper och båda typerna av relationer. Här är ett exempel på en anpassad metod som visar hur du kombinerar ovanstående anpassade metoder för detta ändamål.

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

Du kan nu anropa den här anpassade funktionen så här:

await CustomMethod_FetchAndPrintTwinAsync(srcId, client);

Uppdatera relationer

Relationer uppdateras med hjälp av UpdateRelationship metoden .

Kommentar

Den här metoden är till för att uppdatera egenskaperna för en relation. Om du behöver ändra källtvillingen eller måltvillingen för relationen måste du ta bort relationen och återskapa en med hjälp av de nya tvillingarna.

De obligatoriska parametrarna för klientanropet är:

  • ID för källtvillingen (tvillingen där relationen kommer).
  • ID för relationen som ska uppdateras.
  • Ett JSON Patch-dokument som innehåller de egenskaper och nya värden som du vill uppdatera.

Här är ett exempelkodfragment som visar hur du använder den här metoden. I det här exemplet används SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.

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

}

Här är ett exempel på ett anrop till den här anpassade metoden som skickar in ett JSON Patch-dokument med information om att uppdatera en egenskap.

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

Ta bort relationer

Den första parametern anger källtvillingen (tvillingen där relationen kommer). Den andra parametern är relations-ID:t. Du behöver både tvilling-ID:t och relations-ID:t eftersom relations-ID:t bara är unika inom omfånget för en tvilling.

Här är exempelkoden som visar hur du använder den här metoden. I det här exemplet används SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.

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

Du kan nu anropa den här anpassade metoden för att ta bort en relation som den här:

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

Kommentar

Om du vill ta bort alla modeller, tvillingar och relationer i en instans samtidigt använder du API:et Ta bort jobb.

Skapa flera grafelement samtidigt

I det här avsnittet beskrivs strategier för att skapa ett diagram med flera element samtidigt, i stället för att använda enskilda API-anrop för att ladda upp modeller, tvillingar och relationer för att ladda upp dem en i taget.

Ladda upp modeller, tvillingar och relationer i grupp med API:et Importera jobb

Du kan använda API:et Importera jobb för att ladda upp flera modeller, tvillingar och relationer till din instans i ett enda API-anrop, vilket effektivt skapar grafen samtidigt. Den här metoden kräver användning av Azure Blob Storage, samt skrivbehörigheter i din Azure Digital Twins-instans för grafelement (modeller, tvillingar och relationer) och massjobb.

Om du vill importera resurser i grupp börjar du med att skapa en NDJSON-fil som innehåller information om dina resurser. Filen börjar med ett Header avsnitt följt av de valfria avsnitten Models, Twinsoch Relationships. Du behöver inte inkludera alla tre typerna av grafdata i filen, men alla avsnitt som finns måste följa den ordningen. Tvillingar som definierats i filen kan referera till modeller som antingen definieras i den här filen eller som redan finns i instansen, och de kan också inkludera initiering av tvillingens egenskaper. Relationer som definierats i filen kan referera till tvillingar som antingen definieras i den här filen eller som redan finns i instansen, och de kan också inkludera initiering av relationsegenskaper.

Du kan visa en exempelimportfil och ett exempelprojekt för att skapa dessa filer i introduktionen för API:et Importera jobb.

Därefter måste filen laddas upp till en tilläggsblob i Azure Blob Storage. Anvisningar om hur du skapar en Azure Storage-container finns i Skapa en container. Ladda sedan upp filen med den uppladdningsmetod du föredrar (vissa alternativ är Kommandot AzCopy, Azure CLI eller Azure-portalen).

När NDJSON-filen har laddats upp till containern hämtar du dess URL i blobcontainern. Du använder det här värdet senare i brödtexten i API-anropet för massimport.

Här är en skärmbild som visar URL-värdet för en blobfil i Azure-portalen:

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

Sedan kan filen användas i ett API-anrop för importjobb. Du anger bloblagrings-URL:en för indatafilen samt en ny bloblagrings-URL för att ange var du vill att utdataloggen ska lagras när den skapas av tjänsten.

Importera graf med Azure Digital Twins Explorer

Azure Digital Twins Explorer är ett visuellt verktyg för att visa och interagera med tvillingdiagrammet. Den innehåller en funktion för att importera en graffil i JSON- eller Excel-format som kan innehålla flera modeller, tvillingar och relationer.

Detaljerad information om hur du använder den här funktionen finns i Import graph i dokumentationen för Azure Digital Twins Explorer.

Skapa tvillingar och relationer från en CSV-fil

Ibland kan du behöva skapa tvillinghierarkier av data som lagras i en annan databas, eller i ett kalkylblad eller en CSV-fil. Det här avsnittet visar hur du läser data från en CSV-fil och skapar ett tvillingdiagram av den.

Tänk på följande datatabell som beskriver en uppsättning digitala tvillingar och relationer. Modellerna som refereras i den här filen måste redan finnas i Azure Digital Twins-instansen.

Model ID Tvilling-ID (måste vara unikt) Relationsnamn Måltvilling-ID Dubbla init-data
dtmi:example:Floor; 1 Våning 1 innehåller Rum 1
dtmi:example:Floor; 1 Golv 0 innehåller Rum0
dtmi:example:Room; 1 Rum 1 {"Temperatur": 80}
dtmi:example:Room; 1 Rum0 {"Temperatur": 70}

Ett sätt att hämta dessa data till Azure Digital Twins är att konvertera tabellen till en CSV-fil. När tabellen har konverterats kan kod skrivas för att tolka filen till kommandon för att skapa tvillingar och relationer. Följande kodexempel visar hur du läser data från CSV-filen och skapar ett tvillingdiagram i Azure Digital Twins.

I koden nedan kallas CSV-filen data.csv och det finns en platshållare som representerar värdnamnet för din Azure Digital Twins-instans. Exemplet använder också flera paket som du kan lägga till i projektet för att hjälpa till med den här processen.

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

Exempel på runnable twin graph

Följande runnable-kodfragment använder relationsåtgärderna från den här artikeln för att skapa ett tvillingdiagram av digitala tvillingar och relationer.

Konfigurera exempelprojektfiler

Kodfragmentet använder två exempelmodelldefinitioner, Room.json och Floor.json. Om du vill ladda ned modellfilerna så att du kan använda dem i koden använder du dessa länkar för att gå direkt till filerna i GitHub. Högerklicka sedan var som helst på skärmen, välj Spara som i webbläsarens högerklicka-meny och använd fönstret Spara som för att spara filerna som Room.json och Floor.json.

Skapa sedan ett nytt konsolappprojekt i Visual Studio eller valfri redigerare.

Kopiera sedan följande kod för det körbara exemplet till projektet:

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

Kommentar

Det finns för närvarande ett känt problem som påverkar omslutningsklassen DefaultAzureCredential som kan leda till ett fel vid autentisering. Om du stöter på det här problemet kan du prova att instansiera DefaultAzureCredential med följande valfria parameter för att lösa det: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });

Mer information om det här problemet finns i Kända problem med Azure Digital Twins.

Konfigurera projekt

Slutför sedan följande steg för att konfigurera projektkoden:

  1. Lägg till filerna Room.json och Floor.json som du laddade ned tidigare i projektet och ersätt <path-to> platshållarna i koden för att berätta för programmet var de finns.

  2. Ersätt platshållaren <your-instance-hostname> med azure Digital Twins-instansens värdnamn.

  3. Lägg till två beroenden i projektet som behövs för att arbeta med Azure Digital Twins. Den första är paketet för Azure Digital Twins SDK för .NET och det andra innehåller verktyg för att hjälpa till med autentisering mot Azure.

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

Du måste också konfigurera lokala autentiseringsuppgifter om du vill köra exemplet direkt. Nästa avsnitt går igenom den här processen.

Konfigurera lokala Azure-autentiseringsuppgifter

Det här exemplet använder DefaultAzureCredential (en del av biblioteket) för att autentisera Azure.Identity användare med Azure Digital Twins-instansen när du kör den på den lokala datorn. Mer information om olika sätt som en klientapp kan autentisera med Azure Digital Twins finns i Skriva kod för appautentisering.

Med DefaultAzureCredentialsöker exemplet efter autentiseringsuppgifter i din lokala miljö, till exempel en Azure-inloggning i ett lokalt Azure CLI eller i Visual Studio eller Visual Studio Code. Därför bör du logga in på Azure lokalt via någon av dessa mekanismer för att konfigurera autentiseringsuppgifter för exemplet.

Om du använder Visual Studio eller Visual Studio Code för att köra kodexempel kontrollerar du att du är inloggad i redigeringsprogrammet med samma Azure-autentiseringsuppgifter som du vill använda för att komma åt din Azure Digital Twins-instans. Om du använder ett lokalt CLI-fönster kör az login du kommandot för att logga in på ditt Azure-konto. När du sedan kör kodexemplet bör du autentiseras automatiskt.

Kör exemplet

Nu när du har slutfört installationen kan du köra exempelkodprojektet.

Här är programmets konsolutdata:

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

Dricks

Tvillingdiagrammet är ett begrepp för att skapa relationer mellan tvillingar. Om du vill visa den visuella representationen av tvillingdiagrammet kan du läsa avsnittet Visualisering i den här artikeln.

Nästa steg

Lär dig mer om att köra frågor mot ett Azure Digital Twins-tvillingdiagram: