كيفية الحفاظ على معلومات حالة COM+ في دلفي
ليو شياو مينغ (سيفيرليو)
تبدأ المشكلة على النحو التالي: أحتاج إلى كتابة COM+ للاتصال بقواعد بيانات مختلفة. قد يقول بعض الأصدقاء أنه يجب إنشاء COM+ لكل قاعدة بيانات، لكن هذا لا يمكن القيام به في نظامي. نحن نصنع نظامًا للمساعدة التعليمية، والمستخدمون هم المدارس (بما في ذلك المعلمون والطلاب وأولياء الأمور في المدرسة بالطبع). نقوم ببناء قاعدة بيانات لكل مدرسة. وبطبيعة الحال، لدينا أيضًا قاعدة بيانات إدارية لتنسيق العلاقات بين قواعد البيانات. في كل مرة يتم إضافة مستخدم للمدرسة، نقوم بتنشيط قاعدة بيانات جديدة ليستخدمها العميل. بمعنى آخر، عدد قواعد البيانات لدينا يتزايد باستمرار، ولدينا عميل واحد فقط ولن نقوم بتطوير قواعد بيانات مختلفة لكل مدرسة من جانب العميل، لدينا مجموعة واحدة فقط من COM+، بدلاً من تطوير مجموعة واحدة لكل قاعدة بيانات. لذا يجب أن أسمح له بالاتصال بقواعد بيانات مختلفة بناءً على هوية المستخدم في COM+.
من الواضح أن COM+ هذا يجب أن يوفر طريقة للسماح للمتصل به (والذي يمكن أن يكون تطبيق عميل أو برنامج وسيط آخر) بتحديد قاعدة البيانات للاتصال بها. في الممارسة العملية، نقوم بالاستعلام عن قاعدة البيانات في مكتبة الإدارة بناءً على معرف المستخدم الخاص بها اسم قاعدة البيانات، ثم اتصل بقاعدة بيانات المستخدم هنا، لتبسيط المشكلة، نعتقد أن المتصل يعرف بالفعل اسم قاعدة البيانات، ويطلب مباشرة استدعاء قاعدة البيانات هذه.
قم بإضافة عضو خاص DBName:string إلى فئة COM+ لحفظ اسم قاعدة البيانات المراد الاتصال بها. يجب علينا أيضًا توفير مثل هذه الطريقة لتحديد قيمتها، وقد كتبتها في البداية بهذه الطريقة
PROcedure TmtsDBConn.ConnectTo(sDBName:string);
يبدأ
يحاول
DBName:=sDBName;
SetComplete;
يستثني
SetAbort;
نهاية؛
نهاية؛
ثم ضع عناصر التحكم ADOConnection وADODataSet وDataSetProvider فيها، والتي تسمى adoc وadods وdsp على التوالي. قم بتعيين علاقة الاتصال بينهما، وقم بتعيين سلسلة اتصال adoc إلى قاعدة بيانات الاتصال "DB1"، وهي القيمة الافتراضية، ثم في حدث BeforeConnect الخاص بـ adoc:
adoc.ConnectionString:=ConnectStringA+'Initial Catalog='+DBName+';'+ConnectStringC;
ConnectStringA وConnectStringC هنا عبارة عن ثوابت سلسلة محددة مسبقًا من أجل إنشاء سلسلة الاتصال ديناميكيًا، كما يلي:
ثابت
ConnectStringA='Provider=SQLOLEDB.1;PassWord=2003;معلومات الأمان المستمرة=True;معرف المستخدم=sa;';
ConnectStringB='الكتالوج الأولي=DB1;';
ConnectStringC='مصدر البيانات=server3;إجراء الاستخدام للتحضير=1;الترجمة التلقائية=صحيح;حجم الحزمة=4096;معرف محطة العمل=LXM;استخدام التشفير للبيانات=خطأ;وضع علامة مع ترتيب الأعمدة عندما يكون ذلك ممكنًا=خطأ';
ترجمة وتثبيت هذا COM +. ثم اكتب برنامج عميل للاتصال به.
ضع DCOMConnection في برنامج العميل، واتصل به واكتب خادم COM+، ثم ضع ClientDataSet، وقم بتعيين خصائص RemoteServer وProvider، ثم اكتب عبارات SQL في CommandText الخاص به. ثم قم بوضع عنصر التحكم DataSource وعنصر التحكم DBGrid لتأسيس الاتصال بينهما. أخيرًا، ضع الزر وفي حدث النقر الخاص به:
Dcomconnection1.Connected:=true;
Dcomconnection1.AppServer.connect('DB2');
ClientDataset1.Active:=true;
Dcomconnection1.Connected:=false;
يهدف هذا الرمز إلى اختبار ما إذا كان يمكن الوصول إلى البيانات الموجودة في قاعدة بيانات DB2. ولكن النتيجة هي أنه عند الضغط على الزر يتم الإبلاغ دائمًا عن خطأ ما هو السبب؟
ارجع إلى مشروع COM+، وقم بتصحيحه، وقم بتعيين نقاط التوقف في ConnectTo وadocBeforeConnect، واكتشف أن البرنامج ينفذ إلى
DBName:=sDBName;
عند التنفيذ، تم بالفعل تعيين قيمة DBName على "DB2"، ولكن عند التنفيذ
adoc.ConnectionString:=ConnectStringA+'Initial Catalog='+DBName+';'+ConnectStringC;
، أصبح DBName سلسلة فارغة مرة أخرى، لذلك حدث خطأ.
لماذا فقدت قيمة DBName؟ اتضح أن أسلوب SetComplete يتم استدعاؤه في ConnectTo. تعتقد طريقة SetComplete أن COM+ قد أكمل المهمة وسيقوم بتحرير كائن COM+ لذلك، عند الاتصال بقاعدة البيانات، يتم إنشاء COM+ جديد، ويكون DBName الخاص به بالطبع باطل. .
لقد وجدت السبب، وقمت بتغيير SetComplete إلى EnableCommit، ثم قمت بتشغيل العميل وأخيرًا، تم تشغيله بنجاح واسترجاع البيانات في قاعدة بيانات DB2.
ومع ذلك، في برنامج العميل، قمت بوضع ClientDataSet آخر. بعد فتح ClientDataSet1، قمت بفتح ClientDataSet2 وأردت مواصلة الوصول إلى البيانات في DB2، ولكن تم الإبلاغ عن خطأ آخر. تغيير البرنامج الى
Dcomconnection1.AppServer.connect('DB2');
ClientDataset1.Active:=true;
ClientDataset1.Active:=false;
ClientDataset1.Active:=true;
حتى إذا تم استخدام ClientDataSet واحد فقط، فسيظل يحدث خطأ عند فتحه مرة أخرى بعد إغلاقه.
ولكن إذا كتب العميل
Dcomconnection1.AppServer.connect('DB2');
ClientDataset1.Active:=true;
Dcomconnection1.AppServer.connect('DB2');
ClientDataset2.Active:=true;
يمكن تنفيذها بنجاح. ولكن هذا يبدو قبيحًا للغاية، لماذا يطلق COM+ نفسه بعد الاتصال بقاعدة البيانات؟
اتضح أن TmtsDataModule لديه سمة الإكمال التلقائي، والقيمة الافتراضية صحيحة، لذلك بعد الاتصال بقاعدة البيانات، ستظل تحرر نفسها.
بعد تعيين الإكمال التلقائي على خطأ، لا يزال هناك خطأ في التتبع في حدث OnActivate لـ COM+، حيث وجد أنه عند تنشيطه، تم تعيين سمة الإكمال التلقائي تلقائيًا على صواب، لذلك بعد اتصاله بقاعدة البيانات لأول مرة، استمر في تحرير نفسه. .
في حدث OnOnActivate لـ COM+، اكتب:
الإكمال التلقائي:=خطأ;
لا توجد مشكلة إذا اتصل العميل مرة واحدة وقام بالوصول إلى قاعدة البيانات عدة مرات.
ولكن في هذه الحالة، لن يتم تحرير COM+ تلقائيًا. ستحتاج إلى إضافة أسلوب إلى COM+، وSetComplete في هذه الطريقة، ثم استدعاء هذا الأسلوب لتحرير COM+ بعد انتهاء العميل من COM+.
بعد الاستكشاف أعلاه، توصلنا إلى الاستنتاج التالي: في COM+، إذا كنت ترغب في الحفاظ على معلومات الحالة، فأنت بحاجة إلى القيام ببعض الأعمال، لأن COM+ افتراضيًا عديم الحالة، في كل مرة يتم استدعاؤها من قبل العميل، فإنه سيحكم على ما إذا كان ذلك أم لا يجب أن يحرر نفسه، إذا لم نرغب في تحريره، فعلينا أن نتدخل يدويًا، وفي النهاية يتعين علينا تحريره يدويًا.