إدارة رسم بياني للتوائم الرقمية باستخدام العلاقات
قلب Azure Digital Twins هو الرسم البياني المزدوج الذي يمثل بيئتك بأكملها. يتكون الرسم البياني التوأم من توائم رقمية فردية متصلة عبر العلاقات. تركز هذه المقالة على إدارة العلاقات والرسم البياني ككل. للعمل مع التوائم الرقمية الفردية، راجع إدارة التوائم الرقمية.
بمجرد أن يكون لديك مثيل Azure Digital Twins يعمل وتقوم بإعداد رمز المصادقة في تطبيق العميل الخاص بك، يمكنك إنشاء التوائم الرقمية وعلاقاتها وتعديلها وحذفها في مثيل Azure Digital Twins.
المتطلبات الأساسية
للعمل مع Azure Digital Twins في هذه الوحدة، تحتاج أولاً إلى إعداد نمذجة Digital Twins. تحتاج أيضاً إلى الأذونات المطلوبة لاستخدامه. إذا كانت لديك بالفعل نمذجة لـ Azure Digital Twins تم إعدادها، فيمكنك استخدامه بدلاً من ذلك.
وإلا، فاتبع الإرشادات الموجودة في إعداد نمذجة ومصادقة. تحتوي الإرشادات على معلومات لمساعدتك في التحقق من إكمال كل خطوة بنجاح.
بعد إعداد النمذجة الخاصة بك، دون ملاحظة للقيم التالية. ستحتاج إلى هذه القيم للوصول لاحقاً إلى هذه النمذجة:
- اسم مضيفالنمذجة. يمكنك العثور على اسم المضيف في بوابة Azure.
- اشتراك Azure الذي استخدمته لإنشاء النمذجة. سيُفعل إما بالاسم وإما بالمعرف. يمكنك العثور على الاشتراك في صفحة نظرة عامة حول النمذجة الخاصة بك في بوابة Azure.
واجهات المطور
توضح هذه المقالة كيفية إكمال عمليات الإدارة المختلفة باستخدام .NET (C#) SDK. يمكنك أيضا صياغة استدعاءات الإدارة نفسها باستخدام مجموعات SDK باللغات الأخرى الموضحة في واجهات برمجة تطبيقات Azure Digital Twins ومجموعات SDK.
تتضمن واجهات المطورين الأخرى التي يمكن استخدامها لإكمال هذه العمليات ما يلي:
عرض البيانات بشكل بياني
Azure Digital Twins Explorer هو أداة مرئية لاستكشاف البيانات الموجودة في الرسم البياني لتوائم Azure الرقمية. يمكنك استخدام المستكشف لعرض النماذج والتوائم والعلاقات والاستعلام عنها وتحريرها.
للقراءة حول أداة Azure Digital Twins Explorer، راجع Azure Digital Twins Explorer. للحصول على خطوات مفصلة حول كيفية استخدام ميزاته، راجع استخدام Azure Digital Twins Explorer.
إليك الشكل الذي يبدو عليه التصور:
إنشاء علاقات
تصف العلاقات كيف ترتبط التوائم الرقمية المختلفة ببعضها البعض، والتي تشكل أساس الرسم البياني التوأم.
يتم تعريف أنواع العلاقات التي يمكن إنشاؤها من توأم (مصدر) إلى توأم آخر (مستهدف) كجزء من نموذج DTDL الخاص بتوأم المصدر. يمكنك إنشاء مثيل لعلاقة باستخدام CreateOrReplaceRelationshipAsync() استدعاء SDK مع التوائم وتفاصيل العلاقة التي تتبع تعريف DTDL.
لإنشاء علاقة، عليك تحديد:
- معرف التوأم المصدر (
srcIdفي نموذج التعليمات البرمجية أدناه): معرف التوأم حيث تنشأ العلاقة. - معرف التوأم المستهدف (
targetIdفي نموذج التعليمات البرمجية أدناه): معرف التوأم حيث تصل العلاقة. - اسم العلاقة (
relNameفي نموذج التعليمات البرمجية أدناه): النوع العام للعلاقة، شيء من هذا القبيل يحتوي على. - معرف العلاقة (
relIdفي نموذج التعليمات البرمجية أدناه): الاسم المحدد لهذه العلاقة، شيء مثل Relationship1.
يجب أن يكون معرف العلاقة فريدًا داخل التوأم المصدر المحدد. لا يلزم أن تكون فريدة من نوعها على مستوى العالم. على سبيل المثال ، بالنسبة للتوأم Foo ، يجب أن يكون كل معرف علاقة محدد فريدا. ومع ذلك ، يمكن أن يكون لشريط توأم آخر علاقة صادرة تتطابق مع نفس معرف علاقة Foo.
يوضح نموذج التعليمات البرمجية التالي كيفية إنشاء علاقة في مثيل Azure Digital Twins. يستخدم استدعاء SDK (مميز) داخل طريقة مخصصة قد تظهر في سياق برنامج أكبر.
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}");
}
}
يمكن الآن استدعاء هذه الوظيفة المخصصة لإنشاء علاقة تحتوي على الطريقة التالية:
await CustomMethod_CreateRelationshipAsync(client, srcId, targetId, "contains", properties);
إذا كنت ترغب في إنشاء علاقات متعددة، يمكنك تكرار المكالمات إلى نفس الطريقة، وتمرير أنواع مختلفة من العلاقات إلى الوسيطة.
لمزيد من المعلومات حول فئة BasicRelationshipالمساعد، راجع واجهات برمجة تطبيقات Azure Digital Twins ومجموعات SDK.
إنشاء علاقات متعددة بين التوائم
يمكن تصنيف العلاقات على أنها إما:
- العلاقات المنتهية ولايته: العلاقات التي تنتمي إلى هذا التوأم والتي تشير إلى الخارج لربطها بالتوائم الأخرى. يتم استخدام طريقة
GetRelationshipsAsync()للحصول على العلاقات الخارجية لتوأم. - العلاقات الواردة: العلاقات التي تنتمي إلى التوائم الأخرى التي تشير إلى هذا التوأم لإنشاء رابط "وارد". يتم استخدام طريقة
GetIncomingRelationshipsAsync()للحصول على العلاقات الواردة من التوأم.
لا توجد قيود على عدد العلاقات التي يمكن أن تكون بين توأمين - يمكنك الحصول على أكبر عدد ممكن من العلاقات بين التوائم كما تريد.
هذه الحقيقة تعني أنه يمكنك التعبير عن عدة أنواع مختلفة من العلاقات بين توأمين في وقت واحد. على سبيل المثال ، يمكن أن يكون للتوأم A علاقة مخزنة وعلاقة مصنعة مع التوأم B.
يمكنك حتى إنشاء مثيلات متعددة من نفس النوع من العلاقة بين نفس التوأمين ، إذا كنت تريد. في هذا المثال، يمكن أن يكون للتوأم A علاقتان مخزنتان مختلفتان مع التوأم ب، طالما أن العلاقات لها معرفات علاقات مختلفة.
ملاحظة
لا يتم حاليا دعم سمات DTDL للعلاقات وللعلاقات minMultiplicitymaxMultiplicity في Azure Digital Twins، حتى إذا تم تعريفها كجزء من نموذج، فلن يتم فرضها بواسطة الخدمة. لمزيد من المعلومات، راجع تفاصيل تنفيذ Azure Digital Twins DTDL.
قائمة العلاقات
سرد خصائص علاقة واحدة
يمكنك دائما إلغاء تسلسل بيانات العلاقة إلى نوع من اختيارك. للوصول الأساسي إلى علاقة، استخدم النوع BasicRelationship. تمنحك فئة المساعد BasicRelationship أيضا إمكانية الوصول إلى الخصائص المحددة في العلاقة ، من خلال IDictionary<string, object>ملف . لإدراج الخصائص، يمكنك استخدام:
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}");
}
}
سرد العلاقات الصادرة من توأم رقمي
للوصول إلى قائمة العلاقات الصادرة لتوأم معين في الرسم البياني، يمكنك استخدام الطريقة التالية GetRelationships() :
AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);
تقوم هذه الطريقة بإرجاع Azure.Pageable<T> أو Azure.AsyncPageable<T>، بناءً على ما إذا كنت تستخدم الإصدار المتزامن أو غير المتزامن من المكالمة.
في ما يلي مثال يسترد قائمة بالعلاقات. يستخدم استدعاء SDK (مميز) داخل طريقة مخصصة قد تظهر في سياق برنامج أكبر.
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;
}
}
يمكنك الآن استدعاء هذه الطريقة المخصصة لمعرفة العلاقات المنتهية ولايته للتوائم مثل هذا:
await CustomMethod_FindOutgoingRelationshipsAsync(client, twin_Id);
يمكنك استخدام العلاقات التي تم استردادها للانتقال إلى التوائم الأخرى في الرسم البياني الخاص بك عن طريق قراءة الحقل target من العلاقة التي تم إرجاعها، واستخدامه كمعرف لمكالمتك التالية إلى GetDigitalTwin().
سرد العلاقات الواردة إلى توأم رقمي
يحتوي Azure Digital Twins أيضا على مكالمة SDK للعثور على جميع العلاقات الواردة إلى توأم معين. غالبا ما تكون حزمة SDK هذه مفيدة للتنقل العكسي أو عند حذف توأم.
ملاحظة
IncomingRelationship المكالمات لا تعيد الجسم الكامل للعلاقة. لمزيد من المعلومات حول الفصل، راجع الوثائق المرجعيةIncomingRelationship الخاصة به.
ركزت عينة التعليمات البرمجية في القسم السابق على العثور على العلاقات الصادرة من توأم. يتم تنظيم المثال التالي بشكل مماثل ، ولكنه يجد علاقات واردة مع التوأم بدلا من ذلك. يستخدم هذا المثال أيضا استدعاء SDK (مميز) داخل طريقة مخصصة قد تظهر في سياق برنامج أكبر.
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;
}
}
يمكنك الآن استدعاء هذه الطريقة المخصصة لمعرفة العلاقات الواردة للتوائم مثل هذا:
await CustomMethod_FindIncomingRelationshipsAsync(client, twin_Id);
سرد جميع خصائص وعلاقات التوأم
باستخدام الطرق المذكورة أعلاه لإدراج العلاقات الصادرة والواردة إلى توأم، يمكنك إنشاء طريقة تطبع معلومات التوأم الكاملة، بما في ذلك خصائص التوأم وكلا النوعين من علاقاته. فيما يلي مثال على طريقة مخصصة توضح كيفية الجمع بين الطرق المخصصة المذكورة أعلاه لهذا الغرض.
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;
}
يمكنك الآن استدعاء هذه الوظيفة المخصصة على النحو التالي:
await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
تحديث العلاقات
يتم تحديث العلاقات باستخدام الطريقة UpdateRelationship .
ملاحظة
هذه الطريقة مخصصة لتحديث خصائص العلاقة. إذا كنت بحاجة إلى تغيير التوأم المصدر أو التوأم المستهدف للعلاقة، فستحتاج إلى حذف العلاقةوإعادة إنشاء واحدة باستخدام التوائم الجديدة.
المعلمات المطلوبة لمكالمة العميل هي:
- معرف التوأم المصدر (التوأم الذي تنشأ فيه العلاقة).
- معرف العلاقة بالتحديث.
- مستند JSON Patch يحتوي على الخصائص والقيم الجديدة التي تريد تحديثها.
في ما يلي مقتطف نموذجي للشفرة يوضح كيفية استخدام هذه الطريقة. يستخدم هذا المثال استدعاء SDK (مميز) داخل طريقة مخصصة قد تظهر في سياق برنامج أكبر.
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}");
}
}
في ما يلي مثال على استدعاء إلى هذه الطريقة المخصصة، يتم تمريره في مستند JSON Patch يحتوي على المعلومات اللازمة لتحديث خاصية.
var updatePropertyPatch = new JsonPatchDocument();
updatePropertyPatch.AppendAdd("/ownershipUser", "ownershipUser NEW value");
await CustomMethod_UpdateRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}", updatePropertyPatch);
حذف العلاقات
تحدد المعلمة الأولى المصدر التوأم (التوأم حيث تنشأ العلاقة). المعلمة الأخرى هي معرف العلاقة. أنت بحاجة إلى كل من المعرف المزدوج ومعرف العلاقة، لأن معرفات العلاقة فريدة فقط في نطاق التوأم.
فيما يلي نموذج لتعليمات برمجية يوضح كيفية استخدام هذه الطريقة. يستخدم هذا المثال استدعاء SDK (مميز) داخل طريقة مخصصة قد تظهر في سياق برنامج أكبر.
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}");
}
}
يمكنك الآن استدعاء هذه الطريقة المخصصة لحذف علاقة مثل هذه:
await CustomMethod_DeleteRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}");
إنشاء رسم بياني من ملف CSV
في حالات الاستخدام العملي، غالبا ما يتم إنشاء تسلسلات هرمية مزدوجة من البيانات المخزنة في قاعدة بيانات مختلفة، أو ربما في جدول بيانات أو ملف CSV. يوضح هذا القسم كيفية قراءة البيانات من ملف CSV وإنشاء رسم بياني مزدوج منه.
ضع في اعتبارك جدول البيانات التالي ، الذي يصف مجموعة من التوائم والعلاقات الرقمية.
| معرف النموذج | معرف التوأم (يجب أن يكون فريدا) | اسم العلاقة | معرف التوأم المستهدف | توأم بيانات init |
|---|---|---|---|---|
| dtmi:مثال:الطابق;1 | Floor1 | يحتوي على | غرفة1 | |
| dtmi:مثال:الطابق;1 | Floor0 | يحتوي على | غرفة0 | |
| dtmi:مثال:غرفة;1 | غرفة1 | {"درجة الحرارة": 80} | ||
| dtmi:مثال:غرفة;1 | غرفة0 | {"درجة الحرارة": 70} |
تتمثل إحدى طرق الحصول على هذه البيانات في Azure Digital Twins في تحويل الجدول إلى ملف CSV. بمجرد تحويل الجدول ، يمكن كتابة التعليمات البرمجية لتفسير الملف إلى أوامر لإنشاء توائم وعلاقات. يوضح نموذج التعليمات البرمجية التالي قراءة البيانات من ملف CSV وإنشاء رسم بياني مزدوج في Azure Digital Twins.
في التعليمة البرمجية أدناه، يسمى ملف CSV data.csv، وهناك عنصر نائب يمثل اسم المضيف لمثيل Azure Digital Twins. يستخدم النموذج أيضا العديد من الحزم التي يمكنك إضافتها إلى مشروعك للمساعدة في هذه العملية.
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);
}
}
}
نموذج رسم بياني توأم قابل للتكرار
يستخدم مقتطف التعليمات البرمجية القابل للتشغيل التالي عمليات العلاقة من هذه المقالة لإنشاء رسم بياني مزدوج من التوائم والعلاقات الرقمية.
إعداد نماذج من ملفات المشروع
يستخدم المقتطف تعريفين نموذجيين هما Room.json وFloor.json. لتنزيل ملفات النموذج حتى تتمكن من استخدامها في التعليمات البرمجية، استخدم هذه الارتباطات للانتقال مباشرة إلى الملفات الموجودة في GitHub. بعد ذلك، انقر بزر الماوس الأيمن فوق أي مكان على الشاشة، وحدد حفظ باسم في قائمة النقر بزر الماوس الأيمن في المستعرض، واستخدم نافذة حفظ باسم لحفظ الملفات ك Room.json وFloor.json.
بعد ذلك، قم بإنشاء مشروع تطبيق وحدة تحكم جديد في Visual Studio أو المحرر الذي تختاره.
ثم قم بنسخ التعليمة البرمجية التالية من العينة القابلة للتشغيل إلى المشروع الخاص بك:
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>
}
}
ملاحظة
توجد حاليا مشكلة معروفة تؤثر على DefaultAzureCredential فئة المجمع والتي قد تؤدي إلى حدوث خطأ أثناء المصادقة. إذا واجهت هذه المشكلة، يمكنك محاولة إنشاء DefaultAzureCredential مثيل باستخدام المعلمة الاختيارية التالية لحلها: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });
لمزيد من المعلومات حول هذه المشكلة، راجع استكشاف المشكلات المعروفة وإصلاحها.
تكوين المشروع
بعد ذلك، أكمل الخطوات التالية لتكوين التعليمات البرمجية للمشروع:
أضف ملفات Room.json وFloor.json التي قمت بتنزيلها مسبقا إلى مشروعك، واستبدل العناصر النائبة
<path-to>في التعليمة البرمجية لإخبار البرنامج بمكان العثور عليها.استبدل العنصر النائب
<your-instance-hostname>باسم مضيف مثيل Azure Digital Twins.أضف تبعيتين إلى مشروعك ستكون هناك حاجة إليهما للعمل مع Azure Digital Twins. الأول هو حزمة Azure Digital Twins SDK ل .NET، والثاني يوفر أدوات للمساعدة في المصادقة ضد Azure.
dotnet add package Azure.DigitalTwins.Core dotnet add package Azure.Identity
ستحتاج أيضا إلى إعداد بيانات الاعتماد المحلية إذا كنت تريد تشغيل العينة مباشرة. القسم التالي يسير من خلال هذه العملية.
إعداد بيانات اعتماد Azure المحلية
تستخدم هذه العينة DefaultAzureCredential (جزء من مكتبة Azure.Identity) لمصادقة المستخدمين مع مثيل Azure Digital Twins عند تشغيله على جهازك المحلي. لمزيد من المعلومات حول الطرق المختلفة التي يمكن لتطبيق العميل مصادقتها باستخدام Azure Digital Twins، راجع كتابة تعليمات برمجية لمصادقة التطبيق.
سيبحث النموذج باستخدام DefaultAzureCredential عن بيانات اعتماد في بيئتك المحلية، مثل تسجيل الدخول إلى Microsoft Azure في Azure CLI محلي أو في Visual Studio أو Visual Studio Code. ولهذا السبب، يجب تسجيل الدخول محلياً إلى Microsoft Azure من خلال أحد هذه الآليات المخصصة لإعداد بيانات الاعتماد للنموذج.
إذا كنت تستخدم Visual Studio أو Visual Studio Code لتشغيل نموذج التعليمات البرمجية، فتأكد من تسجيل الدخول إلى هذا المحرر باستخدام بيانات اعتماد Azure نفسها التي تريد استخدامها للوصول إلى مثيل Azure Digital Twins.
وخلاف ذلك، يمكنك تثبيت Azure CLI المحلي وبدء موجه الأوامر على جهازك وتشغيل الأمر az login لتسجيل الدخول إلى حسابك في Microsoft Azure. وبعد تسجيل الدخول وعند تشغيل نموذج التعليمات البرمجية، يجب تسجيل دخولك تلقائياً.
تشغيل النموذج
الآن بعد الانتهاء من الإعداد، يمكنك تشغيل نموذج مشروع التعليمات البرمجية.
إليك إخراج وحدة التحكم للبرنامج:
تلميح
الرسم البياني للتوأم هو مفهوم لخلق علاقات بين التوائم. إذا كنت تريد عرض التمثيل المرئي للرسم البياني المزدوج، فراجع قسم المرئيات في هذه المقالة.
الخطوات التالية
تعرف على كيفية الاستعلام عن رسم بياني توأم ل Azure Digital Twins:

