سؤال

أقوم حاليًا بتحديث نظام قديم يسمح للمستخدمين بإملاء جزء من مخطط أحد جداوله.يمكن للمستخدمين إنشاء وإزالة الأعمدة من الجدول من خلال هذه الواجهة.يستخدم هذا النظام القديم ADO 2.8، ويستخدم SQL Server 2005 كقاعدة بيانات خاصة به (لا تريد حتى معرفة قاعدة البيانات التي كان يستخدمها قبل بدء محاولة تحديث هذا الوحش...لكني استطرادا.=)))

في عملية التحرير نفسها، يمكن للمستخدمين تحديد (وتغيير) قائمة القيم الصالحة التي يمكن تخزينها في هذه الحقول التي أنشأها المستخدم (إذا كان المستخدم يريد تحديد ما يمكن أن يكون في الحقل).

عندما يقوم المستخدم بتغيير قائمة الإدخالات الصالحة لحقل ما، إذا قام بإزالة إحدى القيم الصالحة، يُسمح له باختيار "قيمة صالحة" جديدة لتعيين أي صفوف تحتوي على هذه القيمة (غير الصالحة الآن) بداخلها، بحيث لديهم الآن قيمة صالحة مرة أخرى.

من خلال النظر في الكود القديم، لاحظت أنه معرض بشدة لوضع النظام في حالة غير صالحة، لأن التغييرات المذكورة أعلاه لا تتم ضمن معاملة (لذلك إذا جاء شخص آخر في منتصف العملية المذكورة أعلاه وقام بعمله) التغييرات الخاصة...حسنا، يمكنك أن تتخيل المشاكل التي قد تسبب).

تكمن المشكلة في أنني كنت أحاول حملهم على التحديث ضمن معاملة واحدة، ولكن عندما يصل الرمز إلى الجزء الذي يغير فيه مخطط هذا الجدول، فإن جميع التغييرات الأخرى (تحديث القيم في الصفوف، سواء كان ذلك في الجدول الذي تغير فيه المخطط أم لا ...يمكن أن تكون جداول غير مرتبطة تمامًا حتى) التي تم تكوينها حتى هذه النقطة في المعاملة يبدو أنها تم إسقاطها بصمت.لا أتلقى أي رسالة خطأ تشير إلى أنه تم إسقاطها، وعندما أقوم بالمعاملة في النهاية لا يظهر أي خطأ...ولكن عندما أذهب للبحث في الجداول التي كان من المفترض أن يتم تحديثها في المعاملة، لا توجد سوى الأعمدة الجديدة.لا يتم حفظ أي من التغييرات التي تم إجراؤها غير المخطط.

لقد أثبت البحث على الإنترنت للحصول على إجابات، حتى الآن، أنه مضيعة لبضع ساعات...لذلك أتوجه هنا للحصول على المساعدة.هل حاول أي شخص من قبل إجراء معاملة من خلال ADO تقوم بتحديث مخطط الجدول وتحديث الصفوف في الجداول (سواء كان ذلك الجدول نفسه أو غيره)؟هل هذا غير مسموح به؟هل هناك أي وثائق يمكن أن تكون مفيدة في هذه الحالة؟

يحرر:

حسنًا، لقد قمت بالتتبع، وتم إرسال هذه الأوامر إلى قاعدة البيانات (الشرح بين قوسين)

(لا أعرف ما الذي يحدث هنا، يبدو أنه يتم إنشاء إجراء مخزن مؤقت...؟)


declare @p1
int set @p1=180150003 declare @p3 int
set @p3=2 declare @p4 int set @p4=4
declare @p5 int set @p5=-1

(استرجاع الجدول الذي يحتوي على معلومات التعريف للحقول التي أنشأها المستخدم)


exec sp_cursoropen @p1 output,N'SELECT * FROM CustomFieldDefs ORDER BY Sequence',@p3 output,@p4 output,@p5 output select @p1, @p3, @p4, @p5
go

(أعتقد أن الكود الخاص بي كان يتكرر من خلال القائمة هنا، ويلتقط المعلومات الحالية)


exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,1025,1,1
go
exec sp_cursorfetch 180150003,1028,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go

(يبدو أن هذا هو المكان الذي أقوم فيه بإدخال البيانات المعدلة للتعريفات، وأتصفح كل منها وأقوم بتحديث أي تغييرات حدثت في تعريفات الحقول المخصصة نفسها)


exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=1,@Description='asdf',@Format='U|',@IsLookUp=1,@Length=50,@Properties='U|',@Required=1,@Title='__asdf',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=2,@Description='give',@Format='Y',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_give',@Type='B',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=3,@Description='up',@Format='###-##-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_up',@Type='N',@_Version=1
go 
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=4,@Description='Testy',@Format='',@IsLookUp=0,@Length=50,@Properties='',@Required=0,@Title='_Testy',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=5,@Description='you',@Format='U|',@IsLookUp=0,@Length=250,@Properties='U|',@Required=0,@Title='_you',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=6,@Description='never',@Format='mm/dd/yyyy',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_never',@Type='D',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=7,@Description='gonna',@Format='###-###-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_gonna',@Type='C',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go

(هذا هو المكان الذي يزيل فيه الكود الخاص بي المحذوف من خلال الواجهة قبل بدء هذا الحفظ]...وهو أيضًا الشيء الوحيد بقدر ما أستطيع أن أقول أنه يحدث بالفعل أثناء هذه المعاملة)


ALTER TABLE CustomizableTable DROP COLUMN _weveknown;

(الآن، إذا تم تغيير أي من التعريفات بطريقة تتطلب تغيير خصائص العمود الذي أنشأه المستخدم أو إضافة/إزالة فهارس الأعمدة، فسيتم ذلك هنا، إلى جانب إعطاء قيمة افتراضية لأي صفوف التي لم يكن لها قيمة حتى الآن للعمود المحدد ...لاحظ أنه، بقدر ما أستطيع أن أقول، لا يحدث أي من هذا فعليًا عند انتهاء الإجراء المخزن.)

go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '__asdf'
go
ALTER TABLE CustomizableTable ALTER COLUMN __asdf VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON CustomizableTable ( 
__asdf ASC) WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
select * from IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON 
CustomizableTable ( __asdf ASC) WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
UPDATE CustomizableTable SET [__asdf] = '' WHERE [__asdf] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_give'
go
ALTER TABLE CustomizableTable ALTER COLUMN _give Bit NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__give') DROP INDEX idx__give ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_give] = 0 WHERE [_give] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_up'
go
ALTER TABLE CustomizableTable ALTER COLUMN _up Int NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__up') DROP INDEX idx__up ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_up] = 0 WHERE [_up] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_Testy'
go
ALTER TABLE CustomizableTable ADD _Testy VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__Testy') DROP INDEX idx__Testy ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_Testy] = '' WHERE [_Testy] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_you'
go
ALTER TABLE CustomizableTable ALTER COLUMN _you VarChar(250) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__you') DROP INDEX idx__you ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_you] = '' WHERE [_you] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_never'
go
ALTER TABLE CustomizableTable ALTER COLUMN _never DateTime NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__never') DROP INDEX idx__never ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_never] = '1/1/1900' WHERE [_never] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_gonna'
go
ALTER TABLE CustomizableTable ALTER COLUMN _gonna Money NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__gonna') DROP INDEX idx__gonna ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_gonna] = 0 WHERE [_gonna] IS NULL
go

(إغلاق الصفقة...؟)

exec sp_cursorclose 180150003
go

بعد كل هذا اللغط أعلاه، يتم حذف العمود فقط.يبدو أنه تم تجاهل كل شيء قبله وبعده في المعاملة، ولم تكن هناك رسائل في تتبع SQL للإشارة إلى حدوث خطأ ما أثناء المعاملة.

هل كانت مفيدة؟

المحلول

يستخدم الرمز مؤشرًا من جانب الخادم، وهذا هو الغرض من هذه الاستدعاءات.المجموعة الأولى من المكالمات هي إعداد/فتح المؤشر.ثم جلب الصفوف من المؤشر.وأخيرا إغلاق المؤشر.تشبه تلك sprocs عبارات OPEN CURSOR وFETCH NEXT وCLOSE CURSOR T-SQL.

يجب أن ألقي نظرة فاحصة (وهذا ما سأفعله)، ولكن أعتقد أن هناك شيئًا ما يحدث مع المؤشر من جانب الخادم، والمعاملة المغلفة، وDDL.

بعض الأسئلة الأخرى:

  1. هل تقصد استخدام المؤشرات من جانب الخادم في هذه الحالة؟
  2. هل تستخدم جميع أوامر ADO نفس الاتصال النشط؟

تحديث:

لست متأكدًا تمامًا مما يحدث.

يبدو أنك تستخدم مؤشرات من جانب الخادم حتى تتمكن من استخدام Recordset.Update() لدفع التغييرات مرة أخرى إلى الخادم، بالإضافة إلى تنفيذ عبارات SQL التي تم إنشاؤها لتغيير المخطط وتحديث البيانات في الجدول (الجداول) الديناميكية.باستخدام نفس الاتصال، داخل معاملة صريحة.

لست متأكدًا من تأثير عمليات المؤشر على بقية المعاملة، أو العكس، ولكي أكون صادقًا، فأنا مندهش من أن هذا لا يعمل.

لا أعرف حجم التغيير الذي سيحدث، ولكنني أوصي بالابتعاد عن المؤشرات الموجودة على جانب الخادم وإنشاء عبارات UPDATE لتحديثات الجدول الخاص بك.

آسف لم أتمكن من تقديم المزيد من المساعدة.

راجع للشغل- لقد وجدت المعلومات التالية على المكالمات sp_cursor:

http://jtds.sourceforge.net/apiCursors.html

نصائح أخرى

السلوك الذي تصفه مسموح به.كيف يقوم الكود بإجراء تغييرات على المخطط؟إنشاء SQL بسرعة وتنفيذها من خلال أمر ADO؟أو باستخدام أدوكس؟

إذا كان لديك حق الوصول إلى خادم قاعدة البيانات، فحاول تشغيل تتبع SQL Profiler أثناء اختبار السيناريو الذي حددته.معرفة ما إذا كان التتبع يسجل أي أخطاء/عمليات التراجع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top