لماذا تظهر رسالة "لم يمكن تنفيذ العملية" عند فتح سند مصاريف اعتماد أصل، مع خطأ "conversion from nvarchar to NCLOB is unsupported"؟

Viewed 14

عند فتح سند مصاريف اعتماد أصل (FA Custody Expense / سندات الأصول الثابتة المرتبطة) تظهر للمستخدم رسالة عامة:

لم يمكن تنفيذ العملية

وعند مراجعة ملف اللوج (server log) أجد التفاصيل التالية:

Could not extract column [19] from JDBC ResultSet [The conversion from nvarchar to NCLOB is unsupported.]

الخطأ يبدو متعلقًا بعدم تطابق نوع العمود في قاعدة البيانات مع النوع الذي يتوقعه Hibernate في الكود (الكود يتوقع NCLOB لحقول الملاحظات الطويلة بينما العمود الفعلي في قاعدة البيانات هو NVARCHAR(255)).

أين هو مكان المشكلة؟ وكيف يمكن إصلاحها على قاعدة البيانات بحيث تعمل سندات اعتماد الأصول وما يرتبط بها من جداول الجدولة والاستلام والعهد دون أن أضطر إلى ترقية الإصدار؟

2 Answers

إضافة للإجابة السابقة: نفس الخطأ يتكرر مع جداول أخرى غير المذكورة في القائمة، لأن حقول remark و remarks معرّفة كـ NCLOB في كثير من الجداول عبر النظام كله وليس في الأصول الثابتة فقط. بدل تتبّع كل جدول يظهر في اللوج واحدًا تلو الآخر، شغّل الاستعلام التالي مرة واحدة — فهو يولّد جمل ALTER لكل عمود اسمه remark أو remarks ونوعه ليس NVARCHAR(MAX).

SELECT 'ALTER TABLE [' + s.name + '].[' + t.name + '] ALTER COLUMN [' + c.name + '] NVARCHAR(MAX) '
       + CASE WHEN c.is_nullable = 1 THEN 'NULL' ELSE 'NOT NULL' END + ';' AS AlterStatement
FROM sys.columns  c
JOIN sys.tables   t ON t.object_id = c.object_id
JOIN sys.schemas  s ON s.schema_id = t.schema_id
WHERE c.name IN ('remark', 'remarks')
  AND c.is_computed = 0
  AND TYPE_NAME(c.user_type_id) IN ('nvarchar', 'varchar', 'nchar', 'char', 'ntext', 'text')
  AND NOT (TYPE_NAME(c.user_type_id) = 'nvarchar' AND c.max_length = -1)
ORDER BY t.name, c.name;

الاستعلام لا يعدّل شيئًا بنفسه، بل يخرج عمودًا نصيًا فيه جمل ALTER جاهزة. انسخ ناتج العمود كاملًا، راجعه، ثم نفّذه.

تفاصيل تهمّ:

  • max_length = -1 في sys.columns هي علامة MAX، ولهذا يستثني الشرط الأعمدة السليمة أصلًا ولا يولّد لها جملًا.
  • الجملة المولَّدة تعيد كتابة NULL / NOT NULL كما هي في العمود الحالي، لأن ALTER COLUMN في SQL Server يجعل العمود يقبل NULL إن لم تُذكر، فيضيع قيد NOT NULL.
  • يقتصر التوليد على الأنواع النصية فقط، حتى لا يمسّ الاستعلام أي عمود بنفس الاسم لكن بنوع آخر.

قبل التنفيذ

  • خذ نسخة احتياطية من قاعدة البيانات، ونفّذ من حساب له صلاحية ALTER.
  • لن ينجح التحويل على عمود داخل فهرس (index) أو قيد فريد أو قيد تحقق، لأن NVARCHAR(MAX) لا يُفهرس. إن ظهر خطأ من هذا النوع على عمود بعينه فاحذف الفهرس، نفّذ ALTER، ثم أعد إنشاء الفهرس على عمود آخر أو تجاهل هذا العمود إن لم يظهر في اللوج.
  • نفس الاستعلام يصلح لأي حقل آخر يظهر بنفس رسالة conversion ... to NCLOB is unsupported — غيّر فقط قائمة الأسماء في c.name IN (...).

السبب

عدم تطابق نوع العمود في قاعدة البيانات مع النوع الذي يتوقعه Hibernate. النسخة الحديثة من النظام عرّفت حقول remarks و remark في عدد من جداول الأصول الثابتة (Fixed Assets) كـ NCLOB (يُخزَّن في SQL Server كـ NVARCHAR(MAX))، لكن في قواعد البيانات الأقدم لا تزال هذه الأعمدة من نوع NVARCHAR(255) ولم تتم ترقيتها — فيرفض المحرّك تحويل القيمة وتظهر الرسالة:

The conversion from nvarchar to NCLOB is unsupported.

الحل

نفّذ سكربت تعديل أنواع الأعمدة التالي على قاعدة البيانات. هذا يُحوّل الأعمدة المطلوبة إلى NVARCHAR(MAX) (وهو ما يقابل NCLOB في SQL Server):

ALTER TABLE FACustodyScheduledPayLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAPurchaseScheduledPayLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAPurchaseOrderScheduledPayLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAPurchaseOfferScheduledPay ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAInitialReceiptScheduledPayLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAOpeningDocumentScheduleLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAInitialReceiptLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAPurchaseOfferLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAPurchaseOrderLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAPurchOrderReqLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FALcExpenseLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FALCScheduledPayLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAReceiptDocLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FAScheduleTemplateLine ALTER COLUMN remarks NVARCHAR(MAX);
ALTER TABLE FATakingActualLine ALTER COLUMN remarks NVARCHAR(MAX);

ALTER TABLE CustodyCustodianLine ALTER COLUMN remark NVARCHAR(MAX);
ALTER TABLE FACustodyDeliveryLine ALTER COLUMN remark NVARCHAR(MAX);
ALTER TABLE FACustodyDeliveryEmpLine ALTER COLUMN remark NVARCHAR(MAX);
ALTER TABLE FACustodyTransferFromLine ALTER COLUMN remark NVARCHAR(MAX);
ALTER TABLE FACustodyTransferToLine ALTER COLUMN remark NVARCHAR(MAX);
ALTER TABLE FACustodianLine ALTER COLUMN remark NVARCHAR(MAX);

ملاحظات

  • نفّذ السكربت من حساب له صلاحية ALTER على هذه الجداول، ويُفضّل أخذ نسخة احتياطية قبل التنفيذ.
  • بعض الجداول قد لا تكون موجودة في كل التركيبات — لا تتعطّل بسبب رسالة "object does not exist"، شغّل كل جملة ALTER على حدة وتجاهل الجداول المفقودة.
  • بعد تنفيذ السكربت أعد تشغيل الخادم لإفراغ أي حالة محفوظة في الـ session/cache، ثم أعد فتح سند مصاريف اعتماد الأصل وستعمل بشكل طبيعي.