Skip to content
English

الكيانات الافتراضية (Virtual Entities) — وحدات SQL قابلة لإعادة الاستخدام في التقارير ولوحات المعلومات

ربما مررت بهذا الموقف من قبل: نفس استعلام SQL المعقد يظهر في خمسة سجلات مختلفة من معالج التقارير وثلاثة widgets في لوحة المعلومات. وفي كل مرة تعدّله، عليك أن تتذكر كل مكان حُفظ فيه. علاوة على ذلك، يعرض منتقي الجدول في المعالج الكيانات الحقيقية فحسب، مثل SalesInvoice أو CostInTransLine، وبالتالي فإن أي استعلام يحتاج إلى UNION أو join مكتوب يدويًا أو قلب للإشارة على مستوى الصف لا بد من إعادة كتابته في كل محرر SQL لكل widget.

الكيانات الافتراضية (Virtual Entities) تحل هذه المشكلة. تكتب SELECT واحدة —بقدر ما تشاء من التعقيد: UNION وJOIN وتعبيرات وتجميعات— وتمنحها كودًا واسمًا، فيحولها النظام إلى كيان من الدرجة الأولى. ومن تلك اللحظة، يظهر هذا الكيان في منتقي الجدول الرئيسي في معالج التقارير وفي معالج Widget لوحة المعلومات تمامًا كجدول حقيقي — نفس منتقي الحقول، ونفس الربط التلقائي على الحقول المرجعية، ونفس الترجمات، ونفس لوحة المدخلات.


الفكرة الأساسية في مثال واحد

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

sql
select l.totalCost, l.totalQty, l.item_id, l.legalEntity_id, l.valueDate
from CostInTransLine l
union all
select l.totalCost * -1, l.totalQty * -1, l.item_id, l.legalEntity_id, l.valueDate
from CostOutTransLine l

تحفظ هذا بوصفه كيانًا افتراضيًا يُسمى InTransitMovements. خلف الكواليس، يُنشئ النظام view في SQL Server باسم vw_InTransitMovements، ويسجل تعريف كيان جديد يشير إلى هذا الـ view، ويضيفه إلى النموذج الذي يستشيره المعالجان.

الآن في معالج التقارير، تختار "الجدول الرئيسي → InTransitMovements"، فتحصل على:

  • حقل يُسمى item من النوع Reference → InvItem (لأن item_id في الجدول المصدر يرتبط بهذه الخاصية).
  • حقل يُسمى legalEntity من النوع Reference → LegalEntity.
  • حقل يُسمى valueDate من النوع Date.
  • حقول رقمية totalCost وtotalQty.

يمكنك إضافتها إلى تقرير، والتجميع حسب item، وحساب مجموع التكلفة والكمية، وتكون قد انتهيت. لا يوجد SQL خام في أي مكان في التقرير. كما يمكن اختيار نفس الكيان الافتراضي من معالج Widget لوحة المعلومات — نفس سلوك الربط التلقائي، ونفس الترجمات، ونفس دعم التعمق في البيانات (drill-down).


أين تجده

تتوفر شاشة Virtual Entity في قائمة وحدة Basic. افتحها كما تفتح أي ملف رئيسي: انقر جديد، أكمل ترويسة السجل، وستكون جاهزًا.

تحتوي الترويسة على عدد محدود من الحقول:

  • Code — معرّف قصير، يتكون من حروف أو أرقام أو شرطة سفلية فقط، ويجب أن يبدأ بحرف. يستخدم النظام هذا الكود لتسمية الـ view الأساسي (vw_<code>) وبوصفه اسم نوع الكيان. بمجرد الحفظ، لا يمكن تغيير الكود (إذ يستلزم إعادة التسمية حذف الـ view وإعادة إنشائه، وهو ما لا تتيحه المرحلة الأولى — راجع ما القادم لاحقًا).
  • Arabic Name / English Name — ما سيراه المستخدمون في منتقي الجدول بالمعالج، وفي تسميات الحقول، وعناوين الشاشات.
  • SQL Query — جملة SELECT التي تُعرّف الكيان. متعددة الأسطر؛ استخدم UNION وJOIN والتعبيرات والتجميعات — كل ما تحتاجه.
  • Materialization — في الوقت الحالي، View فقط مسموح به. خيار Table محجوز لمرحلة مستقبلية لتجسيد البيانات في جدول فيزيائي قابل للتحديث.

بعد ملء هذه الحقول، انقر حفظ. ثم لربط أعمدة SELECT بخصائص الكيان، انقر زر Edit Mappings في أعلى الشاشة. يفتح هذا المحرر الذي تحدث فيه المعجزة الحقيقية.


نافذة Edit Mappings

تنقسم النافذة إلى قسمين متراكمين عموديًا.

الأعلى — محرر SQL

محرر Monaco (نفس المحرر المستخدم في VS Code) مع إبراز لغوي لـ SQL وإكمال تلقائي وارتفاع يمتد للشاشة كاملة. عدّل استعلامك بحرية؛ يُحلله النظام أثناء الكتابة لاكتشاف الأعمدة التي يرتبط بها كل خاصية.

فوق المحرر، يقوم زر Bootstrap بالعمل الجوهري: يُحلل SELECT بالكامل، ويمر بكل عمود في مجموعة النتائج، ويحدد الجدول الفيزيائي والعمود الذي أتى منه كل عمود، ويبحث عن الخاصية المطابقة في تعريف كيان ذلك الجدول، ثم يقترح قائمة كاملة من الخصائص. انقره وسيمتلئ القسم السفلي باقتراحات الربط.

TIP

Bootstrap هو نقطة البداية الموصى بها. نادرًا ما ستحتاج إلى كتابة عشرين ربطًا للخصائص يدويًا حين يستطيع المحلل اشتقاقها جميعًا من SQL الخاص بك. فكر فيه كزر "Select Fields" في معالج التقارير — نفس الفكرة، مطبقة على أعمدة الكيانات الافتراضية.

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

الأسفل — قائمة الخصائص

هذا هو الجدول الذي يُعرّف الحقول التي سيراها المعالج. كل صف يمثل خاصية واحدة بالأعمدة التالية:

العمودوظيفته
Column Nameاسم العمود في قائمة SELECT (أو الاسم البديل alias). هذا هو الرابط بين الخاصية وعمود الـ view الأساسي.
Full Nameالاسم المنطقي للخاصية — مثلًا item أو legalEntity أو valueDate. هذا ما يظهر في معرفات الحقول (InTransitMovements.item.code إلخ).
Field TypeReference أو Decimal أو Text أو Date أو Integer أو Boolean إلخ. أنواع Reference تُتيح الربط التلقائي في المعالج.
Reference Toوثيق الصلة فقط حين يكون نوع الحقل Reference — الكيان الذي يشير إليه هذا العمود (مثلًا InvItem لعمود item).
Arabic Name / English Nameالترجمات التي سيراها المستخدمون في منتقي الحقول بالمعالج.

طريقتان لإضافة الصفوف:

  1. انقر "Add Column". يظهر صف فارغ. عنصر تحكم Column Name في ذلك الصف هو منتقٍ على الأعمدة التي وجدها المحلل في SQL — الأعمدة غير المربوطة أولًا (محددة)، ثم المربوطة مسبقًا مع تعليق "pick to overwrite". اختيار عمود يُشغّل Bootstrap على مستوى عمود واحد ويملأ بقية الصف.
  2. استخدم Bootstrap. كما هو موضح أعلاه — يستبدل القائمة بالكامل باقتراح المحلل.

إذا نقرت Bootstrap وكانت صفوف موجودة بالفعل، يطلب النظام تأكيدًا أولًا. وكذلك الحال عند اختيار عمود في صف تحتوي Bootstrap-derived mapping — يسأل قبل الكتابة فوق عملك.

الإبلاغ عن الخصائص اليتيمة (Orphan Flagging)

إذا عدّلت SQL بعد ربط الخصائص، ولم يعد Column Name لإحدى الخصائص يطابق أي عمود في قائمة SELECT الجديدة، تُوسَم الصف بتحذير: "هذا العمود لم يعد موجودًا في استعلام SQL الحالي." لا يحذف النظام أي شيء تلقائيًا — أنت تقرر ما إذا كنت ستُعيد تشغيل Bootstrap، أو تختار عمودًا بديلًا، أو تحذف الصف.

تعيد عملية التحليل نفسها التشغيل بعد ~2.5 ثانية من توقفك عن الكتابة، لذا يتحدث الوسم أثناء عملك.


كيف يُحلّل Bootstrap كل عمود

فهم ما يفعله المحلل يُسهّل التنبؤ بمخرجاته كثيرًا.

لمرجع عمود بسيط مثل l.item_id من CostInTransLine l:

  1. يرى المحلل أن item_id ينتمي إلى الاسم البديل l، الذي هو CostInTransLine.
  2. يبحث عن CostInTransLine في نموذج البيانات ويجد الخاصية التي يكون عمودها الأساسي هو item_id — وهي item.
  3. ينسخ الاسم الكامل للخاصية (item) ونوعها (Reference) والكيان المستهدف (InvItem) والتسميات العربية والإنجليزية إلى الاقتراح.
  4. يُعيد تعيين Column Name على الاقتراح ليكون ما استخدمته في قائمة SELECT، حتى يتوافق اسم عمود الـ view.

النتيجة: صف محلول بالكامل لا يحتاج إلى أي تعديل يدوي.

لتجميع مثل SUM(l.totalCost):

يُصنّف المحلل هذا بوصفه Aggregate Numeric. يحصل الاقتراح على Decimal كنوع حقل، وبلا هدف مرجعي، ويستخدم الاسم البديل في SELECT كاسم العمود. قد ترغب في ملء تسمية أكثر وضوحًا.

لتعبير مثل l.totalCost * -1:

إذا كان التعبير يلف عمودًا أساسيًا واحدًا، يحلّ المحلل بيانات وصف الخاصية لذلك العمود — فـl.totalCost * -1 يُحلَّل بنفس طريقة l.totalCost. إذا جمع التعبير أعمدة متعددة أو استخدم جملة CASE، يرجع المحلل إلى نوع Text بلا مرجع، ويُعلّم الاقتراح بـExpression Partial. أكمل الباقي يدويًا.

لـUNION ALL (أو أي عملية مجموعة):

يمر المحلل بكل فرع ويُحلل الأعمدة موضعًا بموضع. للموضع N، يمر بالفروع بالترتيب ويأخذ أول فرع ينتج اقتراحًا محلولًا بالكامل. ولهذا السبب يعمل هذا:

sql
select 0 as x from a
union all
select x from b

الفرع الأول يحتوي على ثابت في الموضع 0 (لا عمود مصدر). الفرع الثاني لديه b.x. يختار الدمج تحليل الفرع الثاني.


ما الذي يحدث عند الحفظ

تنفيذ الحفظ يمر بثلاث خطوات:

  1. التحقق — شكل الكود، وعدم التعارض في الاسم مع كيان موجود، وكون Materialization هو View، وأن SQL غير فارغ.
  2. إعادة بناء XML لنموذج البيانات — يُحوَّل JSON الخاص بالربط إلى تعريف DMEntity (بنفس الشكل الذي يمتلكه كل كيان آخر) ويُخزَّن على السجل.
  3. View DDL — يُشغّل النظام DROP VIEW IF EXISTS dbo.vw_<code> ثم CREATE VIEW dbo.vw_<code> AS <your SELECT> داخل نفس معاملة قاعدة البيانات لحفظ الكيان. إذا فشل View DDL — خطأ نحوي، أو عمود مفقود، أو ORDER BY غير قانوني بدون TOP، أو مشكلة صلاحيات — تُلغى المعاملة بأكملها وترى خطأ SQL Server مباشرةً. لا يُثبَّت أي شيء جزئي.

بعد اكتمال الحفظ، تُعاد بناء ذاكرة التخزين المؤقت لنموذج البيانات حتى يرى الاستدعاء التالي لمعالج التقارير أو معالج Widget لوحة المعلومات الكيان الجديد في منتقي الجدول الرئيسي. لا يلزم إعادة التشغيل ولا مسح يدوي للتخزين المؤقت.


استخدام الكيانات الافتراضية في معالج التقارير

افتح معالج التقارير، انقر الجدول الرئيسي، وسيظهر كيانك الافتراضي جانبًا الكيانات الحقيقية. يعرضها المنتقي تحت نوع الجدول Virtual Entity (بالتوازي مع Entity وDetail Line وSystem Table).

من هنا يعمل كل شيء كما لو كنت على جدول حقيقي:

  • اختيار الحقول — انقر Select Fields وسترى قائمة الخصائص التي عرّفتها: item وlegalEntity وvalueDate وtotalCost وtotalQty. تتوسع الحقول المرجعية تلقائيًا لمنحك item.code وitem.name1 وitem.name2 إلخ.
  • المدخلات — أضف valueDate كمدخل بنوع فلتر Between وستحصل على موجه نطاق التاريخ القياسي.
  • التجميعات — أضف totalCost وtotalQty كمقاييس، وجمّع حسب item، واحصل على تقرير مُجمَّع.
  • الترجمات — تظهر الأسماء العربية والإنجليزية التي حددتها لكل خاصية كعناوين للأعمدة.

راجع دليل معالج التقارير للاطلاع على بقية آليات المعالج — وهي جميعًا تنطبق دون تغيير.


استخدام الكيانات الافتراضية في معالج Widget لوحة المعلومات

في وحدة Dashboard، عند إنشاء widget مدعوم بمصدر بيانات من المعالج، يظهر نفس منتقي الجدول الرئيسي مع كيانك الافتراضي مدرجًا فيه. بمجرد اختياره، تعمل كل ميزات BI التي تحصل عليها الـ widgets المدعومة بالمعالج — التعمق حسب المحدد (dimension drill-by)، وأعمدة cross-filter المستنتجة تلقائيًا، ومنتقيات معرف الحقل — مع الكيان الافتراضي تمامًا كما لو كانت كيانًا حقيقيًا.

هنا تتجلى أكثر فائدة الكيانات الافتراضية: تبنيها مرة واحدة، وبعد ذلك تستطيع إنشاء widgets جديدة للوحة المعلومات بصريًا دون لمس SQL مجددًا.

لمعرفة تفاصيل سلوك الـ widgets المدعومة بالمعالج، راجع دليل وحدة BI ومرجع Wizard Mode.


مثال عملي — تقرير حركات تكاليف البضاعة في الطريق

لنستعرض الخطوات الكاملة من منظور المستخدم باستخدام SQL من بداية الدليل.

الخطوة 1 — إنشاء الكيان الافتراضي

افتح Virtual Entity من قائمة وحدة Basic، انقر جديد، وأدخل:

  • Code: InTransitMovements
  • Arabic Name: حركات البضاعة في الطريق
  • English Name: In-Transit Movements
  • Materialization: View
  • SQL Query:
sql
select l.totalCost, l.totalQty, l.item_id, l.legalEntity_id, l.valueDate
from CostInTransLine l
union all
select l.totalCost * -1, l.totalQty * -1, l.item_id, l.legalEntity_id, l.valueDate
from CostOutTransLine l

احفظ الترويسة.

الخطوة 2 — ربط الأعمدة

انقر Edit Mappings. تفتح النافذة مع SQL محمّل مسبقًا. انقر Bootstrap. تمتلئ قائمة الخصائص:

Column NameFull NameField TypeReference To
totalCosttotalCostDecimal
totalQtytotalQtyDecimal
item_iditemReferenceInvItem
legalEntity_idlegalEntityReferenceLegalEntity
valueDatevalueDateDate

انقر OK. تُغلق النافذة؛ في شاشة الكيان، انقر حفظ. يُنشأ الـ view vw_InTransitMovements ويسجّل الكيان نفسه في نموذج البيانات.

الخطوة 3 — بناء التقرير

افتح معالج التقارير، أنشئ معالجًا جديدًا، واختر In-Transit Movements كجدول رئيسي. أضف الحقول:

  • this — مرجع الكيان (حتى تتمكن من التعمق)
  • item — مربوط تلقائيًا بـ InvItem لأن الخاصية مرجعية
  • valueDate
  • totalQty (مع تجميع Sum)
  • totalCost (مع تجميع Sum)

أضف valueDate كمدخل بنوع فلتر Between. احفظ وشغّل. ستحصل على ملخص لكل صنف يعرض صافي حركة البضاعة في الطريق خلال نطاق التاريخ المحدد، بلا SQL خام في أي مكان بالمعالج.


حالات الحافة والمزالق الشائعة

الحالةما يحدث
SQL لديك يحتوي على خطأ نحوييعرض المحرر شكوى المحلل مباشرة. لا يزال بإمكانك الحفظ، لكن View DDL سيفشل ويظهر خطأ SQL Server.
تشير إلى عمود لم يعد موجودًا في الجدول المصدريفشل View DDL عند الحفظ. أصلح SELECT وحاول مجددًا.
SQL يحتوي على ORDER BY بدون TOPSQL Server يرفض هذا في الـ views. يفشل الحفظ مع خطأ SQL Server. انقل الترتيب إلى التقرير المستهلك عوضًا عن ذلك.
تبني كيانًا افتراضيًا يشير إلى كيان افتراضي آخرمسموح. قاعدة البيانات تفرض اشتراط عدم وجود تبعيات دائرية — إذا أنشأت دائرة عن طريق الخطأ (A → B → A)، سيفشل الأمر الثاني CREATE VIEW.
يحفظ مستخدمان نفس الكيان الافتراضي في الوقت نفسهتعارض القفل التفاؤلي القياسي؛ يفوز حفظ واحد، والآخر يرى خطأ عدم تطابق الإصدار.
تحفظ بدون ربط أي خصائصمسموح. يُنشأ الـ view لكن الكيان لا يحتوي على حقول قابلة للاستخدام في المعالج. أضف الأعمدة لاحقًا.
SQL يحتوي على معامل :placeholderمرفوض عند التحقق. يجب أن يكون SQL للكيان الافتراضي مكتفيًا بذاته.
تغير Code بعد الحفظ الأولمرفوض عند التحقق. أنشئ كيانًا افتراضيًا جديدًا بالكود الجديد إذا أردت إعادة التسمية.

نموذج الثقة — من يجب أن يتمتع بالوصول

تعريف الكيان الافتراضي يُشغّل SQL داخل اتصال قاعدة بيانات التطبيق. لا توجد بيئة معزولة (sandbox): ما يستطيع مستخدم التطبيق فعله، يستطيع SELECT الكيان الافتراضي فعله. وهذا يعني:

  • قيّد قائمة Virtual Entity وصلاحيات تعديل الكيان للمستخدمين المتقدمين / المسؤولين.
  • لا تكشف شاشة إنشاء الكيان للأدوار التي لن تثق بها لكتابة SQL قراءة فقط اعتباطي ضد قاعدة البيانات الإنتاجية.
  • الـ view المُنشأ من SELECT هو view SQL عادي — أي شخص يستطيع قراءة صفوفه يستطيع الاستعلام عنه بحرية بمجرد وجوده، لكن إنشاء/تعديل التعريف هو ما يحتاج إلى تقييد.

ما القادم لاحقًا

تُوفّر المرحلة الأولى الكيانات الافتراضية بوصفها views فقط. يحمل JSON للإعدادات حقولًا متوافقة مستقبلًا للمرحلة التالية، لذا سيتحمّل أي شيء تحفظه الآن التحولات القادمة بسلاسة:

  • Materialization → Table — جداول مُجمَّعة مسبقًا فيزيائيًا للاستعلامات المُكلفة جدًا لتشغيلها عند كل تحميل للوحة المعلومات.
  • سياسات التحديث (Refresh policies) — تحديث يدوي أو مُجدول (cron) أو عند الكتابة للجداول المُجسَّدة.
  • إدارة الفهارس (Index management) — تعريف فهارس على الجدول المُجسَّد لتحسين أداء الاستعلام.
  • إعادة تسمية الكود (Code rename) — حذف الـ view القديم وإنشاء جديد في معاملة واحدة.
  • تتبع التبعيات (Dependency tracking) — معرفة التقارير ولوحات المعلومات والكيانات الافتراضية الأخرى التي تعتمد على كيان افتراضي معين قبل تغييره أو حذفه.

في الوقت الحالي، اعتبر Materialization إشارة خارطة طريق: القائمة المنسدلة تعرض Table معطلًا مع تلميح "Coming later".