تقييم الموضوع :
  • 1 أصوات - بمعدل 5
  • 1
  • 2
  • 3
  • 4
  • 5
[نقاش] الأمر using والتخلص من المتغيرات
#1
حسبما أذكر فإنه عند تعريف متغير باستخدام الأمر using فإن البرنامج يقوم بالتخلص من المتغير بعد الخروج من الحلقة

و إذا استخدمناه لتعريف متغير لنقل من النوع SqlConnection أو SqlCommand فمن المفترض به التخلص من ذلك المتغير بعد الخروج من الحلقة

ولكن في واقع الأمر واجهت مشكلة في أحد تطبيقات asp.net مع vb.net التي أقوم بتنفيذها وهي انتهاء عدد الاتصالات المسموحة بقاعدة البيانات

ولدى مراجعة الكود وجدت أنني أستخدم مثلا Return cmd.ExecuteScalar للعودة من الـ Function والخروج من الوظيفة ولكن في الواقع أن الاتصال بقي مفتوحا بعد الخروج من الوظيفة بهذه الطريقة مع أنه نظريا خرج من حلقة using أيضا بواقع الحال

وكان الحل هو أن أسند القيمة إلى متغير ثم أغلق الاتصال يدويا ثم أعيد القيمة بواسطة return

فبرأيكم ما هو الوضع هنا ولماذا واجهت هذا الاشكال

فمع أنني حللت المشكل وأنهيت البرنامج إلا أنه مازالت قضية فكرية عالقة بالنسبة لي
الرد }}}
تم الشكر بواسطة:
#2
يبدو ان SqlConnection حالة استثنائية ..

وجدت هذا الرابط : http://stackoverflow.com/questions/20203...connection

في شخص جاوب وشرح سبب حدوث المشكلة ، ولكن لم افهم مايقصده Big Grin
الرد }}}
تم الشكر بواسطة: samerselo
#3
المسألة ليست حالة استثنائية بقدر ماهي تعامل مع مصادر خارج تحكم الفجوال بيسيك نفسه

كما نعلم ان محرك إدارة البيانات مستقل عن الفجوال بيسيك، فعندما يتم طلب فتح الاتصال فان الفجوال بيسيك يرسل الطلب لمحرك إدارة البيانات سواء Access أو SQL Server، وسيضل محسوب هذا الاتصال في المحرك إلا أن تقوم بارسال طلب غلق أو تنتهي المدة المحددة في المحرك في حال عدم وجود نشاط.

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

لذلك يجب عدم استخدام Return مع اجراءات Execute الخاصة بطلب تنفيذ عملية ما من محرك البيانات وانما يتم وضعها في متغير مثل Dim res = cmd.ExecuteScalar وبعدها يتم طلب إغلاق الاتصال قبل تدمير الكائن SqlConnection ويمكن بعدها ارجاع القيمة مثل Return res
الرد }}}
#4
كلام الأخ في الرابط تقريبا نفس فكرة الأخ adham2016

تفسير منطقي من كلا الطرفين
الرد }}}
تم الشكر بواسطة:
#5
كلام جميل و منطقي ... احب زي هذي المناقشات و الاسئله

شكرا ع الافاده
اسم معرفي : محمد يحيى
الرد }}}
تم الشكر بواسطة:
#6
جميل أخي adham2016
الرد }}}
تم الشكر بواسطة:
#7
الأخ سامر

أرجو منك أن تكتب لنا الكود الذي تسبب في المشكلة؟
لأني أعتقد أن المشكلة تكمن في عدم وضوح الرؤية لمتي يتم إستخدام جملة Using
خاصة أن هذه الجملة مصممة للتعامل مع اي كلاس يقوم يكون IDisposable interface جزء منه

أيضا لنضع في الاعتبار أنه لا يمكن تخصيص متغيرات و استردادها أثناء استخدام جملة Using  و البديل الأمثل هنا هو استخدام جملة Try Catch Finally End Try خاصة مع الدوال Functions

أو أن يتم بناء كلاس أساسه IDisposable interface
ويكون SqlConnection  و Sqlcommand جزء منه بحيث يتم كتابة الدوال داخل الكلاس الجديد ثم و أخيرا يتم اغلاق Connection و عمل Dispsoe لحميع المتغيرات الموجودة في الكلاس الجديد من خلال الحدث Dispsose
و بعد ذلك يمكنك أن تستخدم الكلاس الجديد مع جملة Using بشكل عادي  لأنه بعد الانتهاء من جملة using سيتم إغلاق Connection
الرد }}}
تم الشكر بواسطة: samerselo , samerselo
#8
هذا مثال عن الأكواد التي اتحدث عنها

كما تلاحظ عبارة Try شئ ثابت لدي في أي إجراء أقوم بتنفيذه

كود :
Public Shared Function AddUserActivityRecord(ByVal UsrNam As String, ByVal FormName As String, ByVal OperationExecuted As String,
                                               ByVal OPER_DESCR As String) As Integer

       Try
           Using con As New SqlConnection(ConfigurationManager.ConnectionStrings("JoyBoxStaff").ConnectionString)
               Dim cmd As New SqlCommand()
               cmd.Connection = con
               cmd.CommandText = "INSERT INTO USER_ACTIVITY (USER_NAME, FORM_NAME, OPERATION_EXECUTED, DATE_AND_TIME, OPERATION_DESCRIPTION) "
               cmd.CommandText &= "VALUES (@USR, @FRN, @OPX, @DTM, @OPERATION_DESCRIPTION)"

               cmd.Parameters.Add("@USR", Data.SqlDbType.NVarChar).Value = UsrNam
               cmd.Parameters.Add("@FRN", Data.SqlDbType.NVarChar).Value = FormName
               cmd.Parameters.Add("@OPX", Data.SqlDbType.NVarChar).Value = OperationExecuted
               cmd.Parameters.Add("@DTM", SqlDbType.DateTime2, 7).Value = DateTime.Now

               cmd.Parameters.Add("@OPERATION_DESCRIPTION", Data.SqlDbType.NVarChar).Value = OPER_DESCR

               cmd.Connection.Open()
               Return cmd.ExecuteNonQuery()
               cmd.Connection.Close()
           End Using
       Catch ex As Exception
           Return -10
       End Try
   End Function
الرد }}}
تم الشكر بواسطة:
#9
بعد رؤية الدالة المستخدمة أعقتد أن كيفية و اسلوب كتابة الكود وخاصة مع جملة Using لا يصلح معه ان نسترد من خلاله أي متغيرات
جملة Using قد تكلفك الكثير في تلك الحالة و البدبل الأمثل جملة Try Catch Finally End Try
أو ان كان ضروريا أن تستخدم جملة Using تحديدا في تلك الحالة انت تحتاج لبناء كلاس منفرد تضع به جميع الدوال و يكون اساسه IDisposable Interface

عموما أن أردت يمكنني ان أضع لك الكود الخاص بهذا الكلاس لاحقا و عليك أنت أن تكمل بناء الكلاس و تضيف له الدوال التي تريدها
الرد }}}
تم الشكر بواسطة: samerselo
#10
ياريت لو تضع لنا مثالا يوضح فكرة الكلاس الذي تتحدث عنه
الرد }}}
تم الشكر بواسطة:



التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم