بالنسبة للاخ سندباد راجع هذا الدرس حيث تقوم بالعمل مع البيانات في الذاكرة تقوم بالحذف والتعديل والاضافة وتستطيع بعدها حفظ كل العمليات دفعة واحدة
او كما بالمثال هنا تنشئ حقول وهمية وتضيف وتعدل تم تقراءها بواسطة Loop عادي وتحفظها بقاعدة البيانات
http://vb4arb.com/vb/showthread.php?tid=29982
واذا كان هناك حفظ بقاعدة البيانات يعني هناك حقول اذا استخدم طريقة جلب الحقول من قاعدة البيانات تم اعمل بالوضع المنفصل تم احفظ يكون افضل من عمل Loop
نضرة خاطفة على هذا المكون
تكمن قوة ClientDataSet في حفظ البيانات في الذاكرة اي انه يمكنك ان تعمل بشكل منفصل عن قاعدة البيانات هو لا يختلف عن اي مكون وصول مثل TTable
المبدأ الاساسي كما قلنا ان يتم حفظ البيانات في الذاكرة سيناريو بسيط يمكنك ان تستلف كابل انترنت في الصباح الباكر تتصل بالنت تحمل قاعدة البيانات الخاصة بك تحذف/تعدل/تضيف و في نهاية اليوم
تعيد استلاف الكابل و تحفظ البيانات الى قاعدة البيانات! عفوا تفكير جزائري... بشكل اخر تريد ان تضيف سجل جديد تفتح الـ DataSet تجعلها على الوضع insert تملئ الحقول و تستدعي Post
هذه الاخيرة ليست كالمعتاد مع ClientDataSet فهي لا تقوم بنقل البيانات الى قاعدة البيانات و انما كما قلت يتم حفض السجل في الذاكرة على انه مضاف و لكي يتم حفظ السجل في قاعدة البيانات يجب ان
تستدعي ApplyUpdate و تمرر عدد اللاخطاء المسموح بها من زاوية اخرى ClientDataSet يمتلك نوعين من البيانات Data و Delta عندما نتحدث عن Data فاننا نتحدث
عن البيانات التي لها ما يكافئها في قاعدة البيانات Delta ليس لها ما يكافئها و انما يتم تسجيل كل التغييرات المحدثة على البيانات فعندما تحذف سجل ما مثلا يتم الاشارة في الـ Delta على ان هذا السجل تم حذفه
عندما تستدعي ApplyUpdate يتم مقارنة الـ Delta و الـ Data و يقوم الـ DataSetProvider بتوليد جمل الـ Sql حسب الطلب لا تقلق هو ذكي كفاية ليفعل ذلك
ClientDataSet يعمل بشكل رائع مع DBExpress ما مشكلة DBExpress مكون SqlDataSet لديه القدرة قراءة و الى الامام فقط ماذا يعني هذا يمكن تحمل جدول Clients
مثلا باستخدام ِSqlDataSet و عرضه في DBGrid يمكن تصفح DBGrid نزولا اذا حاولت الصعود سيفاجئك خطأ !! هذه احد المشاكل لا يتوفر على خاصية Prior !! تقوم بوضع
SqlDataSet و تضع مكون DataSetProvider تربط DataSetProvider الى الـ SqlDataSet تضيف ClientDataSet و تربطه مع DataSetProvider
الان تغلبنا على المشكلة يجيد الـ SqlDataSet قراءة البيانات من قاعدة البيانات يمررها الى DataSetProvider الذي بدوره يمررها الى ClientDataSet كمل تعلم ClientDataSet
لديه القدرة على تخزين البيانات في الذاكرة عندما تستتدعي ApplyUpdate يتم مقارنة Data و Delta يقوم الـ Provider بتوليد جمل الـ Sql و يرسلها بدورة الى SqlDataSet
الذي بدوره يسجلها في قاعدة البيانات و هكذا تم التغلب على مشاكل DBExpress
بما ان ClientDataSet يسجل البيانات في الذاكرة عمليات البحث و الفلترة سريعة للغاية مقارنة بتقنيات وصول اخرى..
...ليس هذا و حسب يمكن للـ ClientDataSet ان يعمل كجدول مفصول تماما عن قاعدة البيانات اي تنشئ جدولا و لا يوجد ما يقابله في قاعدة البيانات و عند التعامل معه فانت تتعامل معه مثلما تتعامل مع اي جدول اخر اضافة حذف تعديل لفعل ذلك ضع المكون نقر باليسار و اختر CreateDataSet ثم DoubleClick و اضق الحقول الخاصة بك ...
هناك مثال كامل للاستخدام مع مكونات Absolute Database لاحظ انها نفس العملية مع اي قواعد بيانات واي مكونات يمكنك تطبيقها على قواعد بيانات Access او SQlServer مثلا
وهنا الكود كامل لمشروع
كود :
unit Main;
interface
{$I CompVer.inc}
uses
{$IFDEF D6H}
Variants,
{$ENDIF}
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, DB, ABSMain, Grids, DBGrids, DBClient, Provider, StdCtrls,
ExtCtrls, DBCtrls;
const
DataBaseFileName: String = '..\..\Data\Demos.abs';
type
TForm1 = class(TForm)
DBGrid1: TDBGrid;
dbDemos: TABSDatabase;
ABSTable: TABSTable;
ABSQuery: TABSQuery;
DataSource: TDataSource;
DataSetProvider: TDataSetProvider;
ClientDataSet: TClientDataSet;
rgDataSet: TRadioGroup;
btnReOpen: TButton;
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
eUpdateSql: TEdit;
Button2: TButton;
Button1: TButton;
DataSetProviderUpdate: TDataSetProvider;
ClientDataSetUpdate: TClientDataSet;
ABSQueryUpdate: TABSQuery;
DBNavigator1: TDBNavigator;
Label2: TLabel;
Label1: TLabel;
Label3: TLabel;
procedure btnReOpenClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ApplyUpdates(DataSet: TDataSet);
private
{ Private declarations }
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
dbDemos.DatabaseFileName := ExtractFilePath(Application.ExeName) + DataBaseFileName;
ClientDataSet.Open;
end;
procedure TForm1.btnReOpenClick(Sender: TObject);
begin
ClientDataSet.Close;
if rgDataSet.ItemIndex = 1 then
DataSetProvider.DataSet := ABSTable
else
DataSetProvider.DataSet := ABSQuery;
ClientDataSet.Open;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ClientDataSet.Close;
end;
procedure TForm1.ApplyUpdates(DataSet: TDataSet);
begin
ClientDataSet.ApplyUpdates(0);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
{$IFDEF D5H}
ClientDataSetUpdate.CommandText := eUpdateSql.Text;
ClientDataSetUpdate.Execute;
ClientDataSet.Open;
ClientDataSet.Refresh;
{$ELSE}
MessageDlg('Supported in Delphi 5 and higher only', mtInformation, [mbOK], 0);
{$ENDIF}
end;
end.
وهنا صورة للمشروع
بالنسبة الى التلوين راجع الكود التالي :
لتلوين النص فقط للخلية التي فيها التنبيه او التحذير او التركيز
كود :
procedure TForm1.DBGrid1DrawColumnCell
(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn;
State: TGridDrawState);
begin
if Table1.FieldByName('Salary').AsCurrency>36000 then
DBGrid1.Canvas.Font.Color:=clMaroon;
DBGrid1.DefaultDrawColumnCell
(Rect, DataCol, Column, State);
end;
لتلوين السطر كاملا الذي فيها التنبيه او التحذير او التركيز
كود :
procedure TForm1.DBGrid1DrawColumnCell
(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn;
State: TGridDrawState);
begin
if Table1.FieldByName('Salary').AsCurrency>36000 then
DBGrid1.Canvas.Brush.Color:=clWhite;
DBGrid1.DefaultDrawColumnCell
(Rect, DataCol, Column, State);
end;
لتلوين الخلية كاملة التي فيها التنبيه او التحذير او التركيز
كود :
procedure TForm1.DBGrid1DrawColumnCell
(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn;
State: TGridDrawState);
begin
if Table1.FieldByName('Salary').AsCurrency>40000 then
begin
DBGrid1.Canvas.Font.Color:=clWhite;
DBGrid1.Canvas.Brush.Color:=clBlack;
end;
if DataCol = 4 then //4 th column is 'Salary'
DBGrid1.DefaultDrawColumnCell
(Rect, DataCol, Column, State);
end;
بالنسبة للسؤال عن الـ DataModule
DataModule هي نفسها
عندما تضيفها يكون اسمها DataModule1 او DataModule2 او DataModule3 وهكذا
وعندما ستحفظها ستحفظها بالاسم الذي تريد
انا اسميها Data1 اسم اقصر واسهل في الكتابة
والوحدة اسميها UntData
بالنسبة للسؤال CheckBox وايضا Combpbox في الاداة DBgrid هناك مكونات جاهزة وموجود منها هنا في قسم المكونات اسمها EhLib
فيها الكثير من المكونات لتحرير البيانات
اذا اردت ان تفعل ذلك بنفسك ومن الصفر سوف نرفق الكود
ايضا لدينا المكون StringGrid ولا يرتبط باي قاعدة بيانات يمكننا ان نضع فيه اي بيانات عن طريق رقم الخلية مثال
كود :
StringGrid1.Cells[0]:='system1';
وبعدها Loop برقم الخلية لقراءة كل الخلايا مثلا
كود :
for int =1 to 10
StringGrid1.Cells[int]:='system1';
ولو كنت افضل استخدام طرق اخرى بديلة اسهل مثل استخدام مكونات تعمل بالذاكرة ولا تتصل بالبيانات