تنفيذ سكربت القاعدة مع انطلاق البرنامج + تحديث التعديلات على القاعدة - ابو ليلى - 24-01-20
تنفيذ سكربت انشاء قاعدة البيانات مع بداية انطلاق البرنامج
تحديث نسخة القاعدة مع بداية اطلاق البرنامج
السلام عليكم و رحمة الله و بركاته.
المقال تتحدث عن كيفية تنفيذ سكربت الانشاء لقواعد 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
احفظه لديك و اضفه الى Resource كما في الصورة السابقة.
تجدر الاشارة هنا الى السطر التالي
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
بالعودة الى موضوعنا السكربت يقوم بانشاء القاعدة و الجداول و البيانات داخل الجداول
كما قمت بانشاء سكربت تحديث للقاعدة يحتوي على :
اضافة حقل جديد الى جدول 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
الدالة تقوم بالبداية بفحص توفر القاعدة بالسيرفر فاذا لم تجدها نسند قيمة المتغير DatabaseNotFound .
في حال وجدنا القاعدة سنقوم بمقارنة بين نسخة البرنامج الحالية و قيمة الحقل 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
توكل على الله و شغل البرنامج و اخبرنا بالنتيجة.
بالتوفيق للجميع (لا تنسونا من دعواتكم).
RE: تنفيذ سكربت القاعدة مع انطلاق البرنامج + تحديث التعديلات على القاعدة - عبد العزيز البسكري - 24-01-20
بارك الله فيك و جزاك خير الجزاء
جزاك الله كل الخير - naserflaha71 - 02-07-21
(24-01-20, 11:55 AM)عبد العزيز البسكري كتب : بارك الله فيك و جزاك خير الجزاء
اخي الكريم اولا اشي الله يجزيك كل خير ويعطيك ليرضيك والله انك صادق وابن حلال هذا العلم الذي ينتفع به الناس وصدقة جارية
اخي الكريم ممكن تكمل معروفك معي انا محااسب شركة واعمل مبرمج على الاكسس واتمنى ان اتعلم لغة الفجوال نت واحلم بتصميم برنامج مبيعات ومشتريات وفواتير وفاعدة اليانات تكون اسك يو ال سيرفر
مابطول عليكصممت برنامج بناء على دروس من اليوتيوب دورة المبيعات الشاملة للاستاذ صبحي الجزازي بس يالا الاسف وصلت لنص البير وما كفيتو لانو كان تعليمه قفزي مايوضح كلشي وماحسنت كفي اذا بتساعدني ببرنامج متواضع وانا الك من الشاكرين والدعاء لك بالخي وجزاك الله الخير سلفا
|