24-01-20, 03:12 AM
تنفيذ سكربت انشاء قاعدة البيانات مع بداية انطلاق البرنامج
تحديث نسخة القاعدة مع بداية اطلاق البرنامج
السلام عليكم و رحمة الله و بركاته.
المقال تتحدث عن كيفية تنفيذ سكربت الانشاء لقواعد SQL SERVER اثناء انطلاق البرنامج.
و تتحدث ايضاً عن تحديث نسخة القاعدة في حال اجريت تعديلات على القاعدة كذلك مع انطلاق البرنامج.
مثال توضيحي:
- طلب مني احد العملاء برنامج قواعد بيانات .
- تم تنفيذ البرنامج و تسليمه للعميل (البرنامج ينشئ القاعدة عن طريق سكربت بشكل اتوماتيكي).
- بعد مضي شهر تم طلب تعديل جديد (التعديل يحتاج الى اضافة حقول جديدة الى جدول او اكثر).
مثل هذه الحالة : يتطلب منك تعديل في بنية القاعدة على الطريقة اليدوية بانشاء الحقول في كل جدول
او بعمل سكربت خاص بكل جدول او تجميعهم و من ثم تنفيذهم في جهة السيرفر.
اما عن طريق ManageMent Stuio او عن طريق تعليمات CMD ... الخ.
- يبقى التنفيذ بالطريقة اليدوية معضلة تحتاج الى الكثير من الوقت و يمكن ان تقع باخطاء غير مرغوب بها.
سنتحدث هنا عن التنفيذ من جهة التطبيق الخاص بنا و مخاطبة السيرفر و تنفيذ المطلوب من انشاء الى تحديث.
في البداية سنناقش مسألة انشاء القاعدة عن طريق السكربت الذي نولده في العادة.
يوجد الكثير من المواضيع التي تتحدث عن إنشاء السكربت في المنتدى (اطلع عليها).
بعد ان نكون قد توفرنا على السكربت الخاص بالانشاء , نبدأ عملنا.
سننشئ مشروع اعتيادي Windows Form Application سميه ما شئت.
سنضيف ملف السكربت الخاص بانشاء القاعدة الى Resource الخاص بالبرنامج كما بالصور.
اذهب الى Solution Explorer --> Add -->New Item ثم مع الصورة اضف
سيفتح لك نافذة جديدة اضف كما بالصورة
تابع الصور
بعدها نفتح الفورم Form1 و نضع عليه DataGridView1 .
نفتح محرر الكود و نناقش بعض التفاصيل.
لدينا اكثر من حالة ممكن ان نواجهها قبل تنفيذ السكربت.
1-حصول خطأ من جهة السيرفر (اخطاء الاتصال)
2-قاعدة البيانات غير موجودة (سيتم تنفيذ سكربت الانشاء).
3-قاعدة البيانات موجودة و بنفس البنية لدينا (سنناقشها بالتفصيل لاحقاً).
4-قاعدة البيانات الموجودة قديمة (التي لدينا احدث ---> سيتم تنفيذ سكربت التحديث).
5-قاعدة البيانات حديثة (لن نعمل شيئ) .
كمثال عملي انا انشئت قاعدة جديدة (ClientDB) لدي تتألف من جدولين
جدول TB_Client فيه اربع حقول و بعض البيانات كما بالصورة
جدول AppInfo فيه حقلين وصف واحد من البيانات كما بالصورة
هذا الجدول سنسجل فيه رقم نسخة البرنامج الذي سنصدره و مع كل تحديث للبرنامج سيتم تسجيل رقم النسخة فيه,و سنعتمد على رقم النسخة فيه لتنفيذ سكربت التحديث.
سكربت انشاء القاعدة كما يلي:
PHP كود :
USE [master]
GO
CREATE DATABASE [ClientDB]
CONTAINMENT = NONE
ON PRIMARY
( NAME = N'ClientDB', FILENAME = N'D:\ClientDB.mdf' , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB )
LOG ON
( NAME = N'ClientDB_log', FILENAME = N'D:\ClientDB_log.ldf' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB )
GO
--- 90=SQL 2005 ---->
EXEC dbo.sp_dbcmptlevel @dbname=N'ClientDB', @new_cmptlevel=120
GO
IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
begin
EXEC [ClientDB].[dbo].[sp_fulltext_database] @action = 'enable'
end
GO
ALTER DATABASE [ClientDB] SET ANSI_NULL_DEFAULT OFF
GO
ALTER DATABASE [ClientDB] SET ANSI_NULLS OFF
GO
ALTER DATABASE [ClientDB] SET ANSI_PADDING OFF
GO
ALTER DATABASE [ClientDB] SET ANSI_WARNINGS OFF
GO
ALTER DATABASE [ClientDB] SET ARITHABORT OFF
GO
ALTER DATABASE [ClientDB] SET AUTO_CLOSE OFF
GO
ALTER DATABASE [ClientDB] SET AUTO_SHRINK OFF
GO
ALTER DATABASE [ClientDB] SET AUTO_UPDATE_STATISTICS ON
GO
ALTER DATABASE [ClientDB] SET CURSOR_CLOSE_ON_COMMIT OFF
GO
ALTER DATABASE [ClientDB] SET CURSOR_DEFAULT GLOBAL
GO
ALTER DATABASE [ClientDB] SET CONCAT_NULL_YIELDS_NULL OFF
GO
ALTER DATABASE [ClientDB] SET NUMERIC_ROUNDABORT OFF
GO
ALTER DATABASE [ClientDB] SET QUOTED_IDENTIFIER OFF
GO
ALTER DATABASE [ClientDB] SET RECURSIVE_TRIGGERS OFF
GO
ALTER DATABASE [ClientDB] SET DISABLE_BROKER
GO
ALTER DATABASE [ClientDB] SET AUTO_UPDATE_STATISTICS_ASYNC OFF
GO
ALTER DATABASE [ClientDB] SET DATE_CORRELATION_OPTIMIZATION OFF
GO
ALTER DATABASE [ClientDB] SET TRUSTWORTHY OFF
GO
ALTER DATABASE [ClientDB] SET ALLOW_SNAPSHOT_ISOLATION OFF
GO
ALTER DATABASE [ClientDB] SET PARAMETERIZATION SIMPLE
GO
ALTER DATABASE [ClientDB] SET READ_COMMITTED_SNAPSHOT OFF
GO
ALTER DATABASE [ClientDB] SET HONOR_BROKER_PRIORITY OFF
GO
ALTER DATABASE [ClientDB] SET RECOVERY FULL
GO
ALTER DATABASE [ClientDB] SET MULTI_USER
GO
ALTER DATABASE [ClientDB] SET PAGE_VERIFY CHECKSUM
GO
ALTER DATABASE [ClientDB] SET DB_CHAINING OFF
GO
ALTER DATABASE [ClientDB] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF )
GO
ALTER DATABASE [ClientDB] SET TARGET_RECOVERY_TIME = 60 SECONDS
GO
ALTER DATABASE [ClientDB] SET DELAYED_DURABILITY = DISABLED
GO
EXEC sys.sp_db_vardecimal_storage_format N'ClientDB', N'ON'
GO
USE [ClientDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[AppInfo](
[Property] [nvarchar](100) NOT NULL,
[Value] [nvarchar](100) NULL
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TB_Client](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Client_Name] [nvarchar](50) NULL,
[Client_Adrs] [nvarchar](100) NULL,
[Client_Phone] [nvarchar](50) NULL,
CONSTRAINT [PK_TB_Client] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT [dbo].[AppInfo] ([Property], [Value]) VALUES (N'Version', N'1.0.0.0')
GO
SET IDENTITY_INSERT [dbo].[TB_Client] ON
GO
INSERT [dbo].[TB_Client] ([ID], [Client_Name], [Client_Adrs], [Client_Phone]) VALUES (1, N'احمد', N'Adrs 1', N'142536')
GO
INSERT [dbo].[TB_Client] ([ID], [Client_Name], [Client_Adrs], [Client_Phone]) VALUES (2, N'علي', N'Adrs 2', N'253624')
GO
INSERT [dbo].[TB_Client] ([ID], [Client_Name], [Client_Adrs], [Client_Phone]) VALUES (3, N'سعيد', N'Adrs 3', N'7521452')
GO
INSERT [dbo].[TB_Client] ([ID], [Client_Name], [Client_Adrs], [Client_Phone]) VALUES (4, N'عبد الله', N'Adrs 4', N'5214632')
GO
INSERT [dbo].[TB_Client] ([ID], [Client_Name], [Client_Adrs], [Client_Phone]) VALUES (5, N'سالي', N'Adrs 5', N'6532142')
GO
SET IDENTITY_INSERT [dbo].[TB_Client] OFF
GO
USE [master]
GO
ALTER DATABASE [ClientDB] SET READ_WRITE
GO
تجدر الاشارة هنا الى السطر التالي
PHP كود :
EXEC dbo.sp_dbcmptlevel @dbname=N'ClientDB', @new_cmptlevel=120
تحديدا الرقم 120 وهو يعني SQL Server 2014
هذا يعني ان تركيب القاعدة سيكون بتوافق مع اصدارة SQL SERVER 2014.
بمعنى انه لن يركب على النسخ الاقدم.
لتتضح الامور اكثر فان SQL SERVER 2014 متوافق مع 100,110,120 اي يقبل الانشاء من :
-SQL SERVER 2008 =100
-SQL SERVER 2008 R2=100
SQL SERVER 2012 =110
-SQL SERVER 2014=120
بينما لا يقبل الانشاء من نسخ SQL SERVER 2005 ذات الرقم 90
حتى نسخة SQL SERVER 2012 تقبل الانشاء من الاصدار 90 الخاص بـ SQL SERVER 2005 فقط
النسخ الحديثة من 2014 و ما بعد لا تقبل الانشاء.
ارقام نسخ الاصدارات
1- SQL SERVER 2005 = 90
2- SQL SERVER 2008 = 100 نسخة محرك القاعدة 10
3- SQL SERVER R2= 100 نسخة محرك القاعدة 10.5
4- SQL SERVER 2012 = 110
5- SQL SERVER 2014 = 120
6- SQL SERVER 2016 = 130
7- SQL SERVER 2017 = 140
8- SQL SERVER 2019 = 150
9- Azure SQL Database managed instance = 150
10- Azure SQL Database single database/elastic pool = 150
نسخة SQL SERVER 2000 القديمة = 80
كل النسخ الحديثة تستوعب النسخ التي قبلها ابتداءً من 2008
لمعلومات اوفى يمكن مراجعة الرابط Compatibility Level
بالعودة الى موضوعنا السكربت يقوم بانشاء القاعدة و الجداول و البيانات داخل الجداول
كما قمت بانشاء سكربت تحديث للقاعدة يحتوي على :
اضافة حقل جديد الى جدول TB_Client .
و تم تعديل قيمة النسخة في حقل رقم النسخة داخل الجدول AppInfo .
بالنسبة لرقم النسخة سناخذه من رقم النسخة الخاصة ببرنامجنا .
اذ ان كل نسخة جديدة محدثة عن سابقتها سنصدرها برقم احدث من السابق .
لتعديل نسخة البرنامج مع كل اصدار حديث يمكنك الذهاب لخصائص المشروع ثم مع الصور
سكربت التحديث كما يلي:
PHP كود :
USE ClientDB
GO
ALTER TABLE TB_Client
ADD Email Nvarchar(100)
GO
UPDATE AppInfo set Value='1.0.0.3' where
Property='Version'
نضيف الملف الى Resource كما فعلنا سابقاً.
تجدر الاشارة الى حذف كلمة GO في اخر السكربت لضرورات خاصة بالكود
الان نأتي الى الكود :
بالرجوع الى التفصيل سابقاً سننشأ مجموعة متغيرات لضبط الحالات التي نواجهها اثناء عملنا .
فضلت جعلها داخل Enum لسهولة الوصول اليها.
PHP كود :
Enum VersionCheck
Failed = 0
Equal
DatabaseIsMoreNew
DatabaseIsOlder
DatabaseNotFound
End Enum
PHP كود :
Private sqlCon As SqlConnection = New SqlConnection()
Private sqlCmd As SqlCommand = New SqlCommand()
PHP كود :
Public Function SetupDatabase() As Boolean
Dim bContinue As Boolean = False
Try
sqlCon.ConnectionString = "Server=.;Integrated Security=true"
sqlCon.Open()
Catch sql_ex As SqlException
MessageBox.Show("فشل الاتصال بالسيرفر " & vbLf & sql_ex.Number.ToString() & " " & sql_ex.Message.ToString())
Return bContinue
End Try
' بعد الاتصال بالسيرفر نجري المقارنة
Select Case CheckVersion()
Case CInt(VersionCheck.Equal)
bContinue = True
Exit Select
Case CInt(VersionCheck.Failed)
bContinue = False
Exit Select
Case CInt(VersionCheck.DatabaseIsOlder)
bContinue = RunScript(Resource1.UpdateClientDB.ToString())
Exit Select
Case CInt(VersionCheck.DatabaseIsMoreNew)
bContinue = False
Exit Select
Case CInt(VersionCheck.DatabaseNotFound)
bContinue = RunScript(Resource1.CreateClientDataBase.ToString())
Exit Select
Case Else
bContinue = False
Exit Select
End Select
Return bContinue
End Function
اذا نجح نكمل الى الدالة CheckVersion الخاصة بفحص عدة امور:
-لم نجد القاعدة ؟
-النسخة قديمة؟
-النسخة حديثة؟
الدالة كما يلي:
PHP كود :
''' <summary>
''' مقارنة نسخة البرنامج الحالية مع رقم النسخة المسجل في القاعدة
''' </summary>
''' <returns></returns>
Public Function CheckVersion() As Integer
Dim v As Version = New Version(Application.ProductVersion.ToString())
Try
'فحص توفر القاعدة في السيرفر
sqlCmd = New SqlCommand("select count(*) from master..sysdatabases where name='ClientDB'", sqlCon)
Dim strResult As String = sqlCmd.ExecuteScalar().ToString()
'اذا لم نجد القاعدة
If strResult = "0" Then
sqlCon.Close()
Return CInt(VersionCheck.DatabaseNotFound)
End If
'جلب رقم النسخة المسجل في القاعدة
sqlCmd = New SqlCommand("SELECT value from ClientDB..AppInfo where property='version'", sqlCon)
strResult = sqlCmd.ExecuteScalar().ToString()
Dim vDb As Version = New Version(strResult)
sqlCon.Close()
'اجراء المقارنة
If vDb = v Then Return CInt(VersionCheck.Equal)
If vDb > v Then Return CInt(VersionCheck.DatabaseIsMoreNew)
If vDb < v Then Return CInt(VersionCheck.DatabaseIsOlder)
Catch sql_ex As SqlException
MessageBox.Show(sql_ex.Number.ToString() & " " & sql_ex.Message.ToString())
Return CInt(VersionCheck.Failed)
Catch system_ex As Exception
MessageBox.Show(system_ex.Message.ToString())
Return CInt(VersionCheck.Failed)
End Try
Return CInt(VersionCheck.Failed)
End Function
في حال وجدنا القاعدة سنقوم بمقارنة بين نسخة البرنامج الحالية و قيمة الحقل Value في الجدول AppInfo وهنا نكون اما 3 حالات:
-ارقام النسخ متساوية نسند قيمة المتغير Equal.
-الرقم في القاعدة اكبر من نسخة البرنامج هذا يعني ان النسخة حديثة, نسند قيمة المتغير DatabaseIsMoreNew.
-الرقم في القاعدة اصغر من نسخة البرنامج هذا يعني ان النسخة قديمة , نسند قيمة المتغير DatabaseIsOlder .
اما في حال حدوث خطأ نسند قيمة المتغير Failed .
انتهى عمل هذه الدالة.
في كل حالة من الحالات السابقة نحن امام اجراء يتناسب مع توجهنا .
فاذا كانت النسخ متشابهة بالارقام او القاعدة لدينا حديثة او حصل فشل فلن نقوم بعمل شيئ.
الحالتين الباقيتين :
اذا لم نجد القاعدة سننشئها بواسطة سكربت الانشاء.
اذا كانت نسخة القاعدة قديمة سنحدثها بواسطة سكربت التحديث.
في كلا الحالتين السابقتين نحن بحاجة الى دالة تقوم بتنفيذ السكربت .
الدالة بسيطة تقوم بتنفيذ جمل SQL اعتيادية .
يتم اخذ الجمل من الملفات التي ارفقناها سابقاً داخل مجلد Resource .
الدالة المسؤولة عن تنفيذ السكربت مقسومة الى جزئين .
الجزء الاول يقوم بتفكيك ملف السكربت الى اسطر و يخزنه في مصفوفة نصية بعد ازالة الكلمة GO من داخل ملف السكربت.
دالة التفكيك:
PHP كود :
Public Function ParseScriptToCommands(ByVal strScript As String) As String()
Dim commands As String()
commands = Regex.Split(strScript, "GO" & vbCrLf, RegexOptions.IgnoreCase)
Return commands
End Function
PHP كود :
''' <summary>
''' تنفيذ السكربت المخزن في المصفوفة النصية
''' </summary>
''' <param name="strFile"></param>
''' <returns></returns>
Public Function RunScript(ByVal strFile As String) As Boolean
Dim strCommands As String()
strCommands = ParseScriptToCommands(strFile)
Dim strCmd As String
Try
If sqlCon.State <> ConnectionState.Open Then sqlCon.Open()
sqlCmd.Connection = sqlCon
For Each strCmd In strCommands
If strCmd.Length > 0 Then
sqlCmd.CommandText = strCmd
sqlCmd.ExecuteNonQuery()
End If
Next
Catch sql_ex As SqlException
MessageBox.Show(sql_ex.Number.ToString() & " " & sql_ex.Message.ToString())
Return False
End Try
Return True
End Function
الدالة سهلة بمجملها
تستلم مصفوفة نصية من عدة اسطر ثم تمر على اسطرها و تنفذ العمليات على السيرفر.
و اخيراً دالة بسيطة لملئ القريد في النموذج لنتأكد من سلامة عملنا
PHP كود :
''' <summary>
''' تعبئة القريد بالبيانات من القاعدة بعد انشائها
''' </summary>
Public Sub PopulateGrid()
Dim strCmd As String = "Select * from [ClientDB].[dbo].[TB_Client]"
Dim da As SqlDataAdapter
da = New SqlDataAdapter(strCmd, sqlCon)
Dim ds As New DataSet
da.Fill(ds, "TB_Client")
DataGridView1.DataSource = ds
DataGridView1.DataMember = "TB_Client"
End Sub
حدث تحميل النموذج للاقلاع بالبرنامج :
PHP كود :
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If SetupDatabase() = False Then
Return
End If
PopulateGrid()
End Sub
كود النموذج كاملاً
PHP كود :
Imports System.Data.SqlClient
Imports System.Text.RegularExpressions
Imports EmmbedSQLSERVER.My.Resources
Public Class Form1
Enum VersionCheck
Failed = 0
Equal
DatabaseIsMoreNew
DatabaseIsOlder
DatabaseNotFound
End Enum
Private sqlCon As SqlConnection = New SqlConnection()
Private sqlCmd As SqlCommand = New SqlCommand()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If SetupDatabase() = False Then
Return
End If
PopulateGrid()
End Sub
Public Function SetupDatabase() As Boolean
Dim bContinue As Boolean = False
Try
sqlCon.ConnectionString = "Server=.;Integrated Security=true"
sqlCon.Open()
Catch sql_ex As SqlException
MessageBox.Show("فشل الاتصال بالسيرفر " & vbLf & sql_ex.Number.ToString() & " " & sql_ex.Message.ToString())
Return bContinue
End Try
' بعد الاتصال بالسيرفر نجري المقارنة
Select Case CheckVersion()
Case CInt(VersionCheck.Equal)
bContinue = True
Exit Select
Case CInt(VersionCheck.Failed)
bContinue = False
Exit Select
Case CInt(VersionCheck.DatabaseIsOlder)
bContinue = RunScript(Resource1.UpdateClientDB.ToString())
Exit Select
Case CInt(VersionCheck.DatabaseIsMoreNew)
bContinue = False
Exit Select
Case CInt(VersionCheck.DatabaseNotFound)
bContinue = RunScript(Resource1.CreateClientDataBase.ToString())
Exit Select
Case Else
bContinue = False
Exit Select
End Select
Return bContinue
End Function
''' <summary>
''' مقارنة نسخة البرنامج الحالية مع رقم النسخة المسجل في القاعدة
''' </summary>
''' <returns></returns>
Public Function CheckVersion() As Integer
Dim v As Version = New Version(Application.ProductVersion.ToString())
Try
'فحص توفر القاعدة في السيرفر
sqlCmd = New SqlCommand("select count(*) from master..sysdatabases where name='ClientDB'", sqlCon)
Dim strResult As String = sqlCmd.ExecuteScalar().ToString()
'اذا لم نجد القاعدة
If strResult = "0" Then
sqlCon.Close()
Return CInt(VersionCheck.DatabaseNotFound)
End If
'جلب رقم النسخة المسجل في القاعدة
sqlCmd = New SqlCommand("SELECT value from ClientDB..AppInfo where property='version'", sqlCon)
strResult = sqlCmd.ExecuteScalar().ToString()
Dim vDb As Version = New Version(strResult)
sqlCon.Close()
'اجراء المقارنة
If vDb = v Then Return CInt(VersionCheck.Equal)
If vDb > v Then Return CInt(VersionCheck.DatabaseIsMoreNew)
If vDb < v Then Return CInt(VersionCheck.DatabaseIsOlder)
Catch sql_ex As SqlException
MessageBox.Show(sql_ex.Number.ToString() & " " & sql_ex.Message.ToString())
Return CInt(VersionCheck.Failed)
Catch system_ex As Exception
MessageBox.Show(system_ex.Message.ToString())
Return CInt(VersionCheck.Failed)
End Try
Return CInt(VersionCheck.Failed)
End Function
''' <summary>
''' قراءة الملف النصي الحاوي على السكربت
''' التخلص من كلمة GO و ادراج كل جملة في سطر
''' GO يجب ازالة كلمة
''' من نهاية الملف
''' </summary>
''' <param name="strScript"></param>
''' <returns>مصفوفة نصية تحتوي على الاسطر المراد تنفيذها</returns>
Public Function ParseScriptToCommands(ByVal strScript As String) As String()
Dim commands As String()
commands = Regex.Split(strScript, "GO" & vbCrLf, RegexOptions.IgnoreCase)
Return commands
End Function
''' <summary>
''' تنفيذ السكربت المخزن في المصفوفة النصية
''' </summary>
''' <param name="strFile"></param>
''' <returns></returns>
Public Function RunScript(ByVal strFile As String) As Boolean
Dim strCommands As String()
strCommands = ParseScriptToCommands(strFile)
Dim strCmd As String
Try
If sqlCon.State <> ConnectionState.Open Then sqlCon.Open()
sqlCmd.Connection = sqlCon
For Each strCmd In strCommands
If strCmd.Length > 0 Then
sqlCmd.CommandText = strCmd
sqlCmd.ExecuteNonQuery()
End If
Next
Catch sql_ex As SqlException
MessageBox.Show(sql_ex.Number.ToString() & " " & sql_ex.Message.ToString())
Return False
End Try
Return True
End Function
''' <summary>
''' تعبئة القريد بالبيانات من القاعدة بعد انشائها
''' </summary>
Public Sub PopulateGrid()
Dim strCmd As String = "Select * from [ClientDB].[dbo].[TB_Client]"
Dim da As SqlDataAdapter
da = New SqlDataAdapter(strCmd, sqlCon)
Dim ds As New DataSet
da.Fill(ds, "TB_Client")
DataGridView1.DataSource = ds
DataGridView1.DataMember = "TB_Client"
End Sub
End Class
توكل على الله و شغل البرنامج و اخبرنا بالنتيجة.
بالتوفيق للجميع (لا تنسونا من دعواتكم).
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال