إضافة حقل محسوب إلى استعلام في وقت التشغيل
-
22-09-2019 - |
سؤال
أحصل على بيانات باستخدام استعلام في Delphi ، وأرغب في إضافة حقل محسوب إلى الاستعلام قبل تشغيله. يستخدم الحقل المحسوب القيم في التعليمات البرمجية وكذلك الاستعلام ، لذا لا يمكنني حسابه في SQL.
أعلم أنه يمكنني إرفاق ملف OnCalcFields
حدث لإجراء الحساب فعليًا ، لكن المشكلة هي بعد إضافة الحقل المحسوب ، لا توجد حقول أخرى في الاستعلام ...
لقد قمت ببعض الحفر ووجدت أنه يتم إنشاء جميع الحقول DEFS ولكن يتم إنشاء الحقول الفعلية فقط
if DefaultFields then
CreateFields
تم تحديد الحقول الافتراضية
procedure TDataSet.DoInternalOpen;
begin
FDefaultFields := FieldCount = 0;
...
end;
مما يشير إلى أنه إذا قمت بإضافة حقول ، فستجد فقط الحقول التي أضفتها.
أود جميع الحقول في الاستعلام وكذلك الحقول التي أضيفها.
هل هذا ممكن أم لا بد لي من إضافة جميع الحقول التي أستخدمها أيضًا؟
المحلول
لدى Delphi الآن خيار الجمع بين الحقول التي تم إنشاؤها التلقائيًا والحقول المحسوبة: data.db.tfieldoptions.autocreatemode تعداد من النوع tfieldsautocreationmode. وبهذه الطريقة يمكنك إضافة الحقول المحسوبة في وقت التشغيل. كتب فرانسوا في إجابته كيفية إضافة حقل في وقت التشغيل.
أنماط مختلفة من tfieldsautocreationmode:
AcexClusive
عندما لا تكون هناك حقول مستمرة على الإطلاق ، يتم إنشاء الحقول التلقائية. هذا هو الوضع الافتراضي.
Accombinecoptured
يتم إنشاء الحقول التلقائية عندما لا تحتوي مجموعة البيانات على حقول مستمرة أو لا توجد سوى حقول مستمرة محسوبة. هذه طريقة مريحة لإنشاء الحقول المحسوبة المستمرة في وقت التصميم والسماح لمجموعة البيانات بإنشاء حقول بيانات تلقائية.
Accombinealways
سيتم إنشاء الحقول التلقائية لحقول قاعدة البيانات عندما لا تكون هناك حقول ثابتة.
نصائح أخرى
لا شيء يمنعك من إنشاء جميع الحقول أولاً في الكود الخاص بك ،
ثم أضف الحقول المحسوبة.
يمكنك إما استخدام "نوع الاختراق" لاستخدام CreateFields المحمية:
type
THackQuery = class(TADOQuery)
end;
[...]
MyQuery.FieldDefs.Update;
THackQuery(MyQuery).CreateFields;
أو استعارة بعض التعليمات البرمجية من CreateFields:
MyQuery.FieldDefs.Update;
// create all defaults fields
for I := 0 to MyQuery.FieldDefList.Count - 1 do
with MyQuery.FieldDefList[I] do
if (DataType <> ftUnknown) and not (DataType in ObjectFieldTypes) and
not ((faHiddenCol in Attributes) and not MyQuery.FIeldDefs.HiddenFields) then
CreateField(Self, nil, MyQuery.FieldDefList.Strings[I]);
ثم قم بإنشاء الحقول المحسوبة:
MyQueryMyField := TStringField.Create(MyQuery);
with MyQueryMyField do
begin
Name := 'MyQueryMyField';
FieldKind := fkCalculated;
FieldName := 'MyField';
Size := 10;
DataSet := MyQuery;
end;
تحتاج إلى إضافة جميع الحقول بالإضافة إلى الحقل المحسوب.
بمجرد إضافة حقل ، يجب عليك إضافة جميع الحقول التي تريدها في مجموعة البيانات.
يطلق دلفي هذه الحقول المستمرة مقابل الحقول الديناميكية. جميع الحقول إما مستمرة أو ديناميكية. لسوء الحظ ، لا يمكنك الحصول على مزيج من كليهما.
شيء آخر يجب ملاحظته من الوثائق
يتم تخزين قوائم مكونات الحقول المستمرة في التطبيق الخاص بك ، ولا تتغير حتى إذا تم تغيير بنية قاعدة البيانات الكامنة وراء مجموعة البيانات.
لذا ، كن حذرًا ، إذا قمت لاحقًا بإضافة حقول إضافية إلى جدول ، فستحتاج إلى إضافة الحقول الجديدة إلى المكون. نفس الشيء مع حذف الحقول.
إذا كنت لا تريد حقًا حقولًا مستمرة ، فهناك حل آخر. على أي شبكة أو عنصر تحكم يجب أن يوضح الحقل المحسوب ، يمكنك رسمه المخصص. على سبيل المثال ، تحتوي العديد من أدوات التحكم في الشبكة على حدث OncustomDraw. يمكنك القيام بحسابك هناك.
إذا كنت تعرف أن تكون أسماء الحقول المحسوبة في وقت التشغيل ، فيمكنك استخدام شيء من هذا القبيل.
var
initing:boolean;
procedure TSampleForm.dsSampleAfterOpen(
DataSet: TDataSet);
var
i:integer;
dmp:tfield;
begin
if not initing then
try
initing:=true;
dataset.active:=false;
dataset.FieldDefs.Update;
for i:=0 to dataset.FieldDefs.Count-1 do
begin
dmp:=DataSet.FieldDefs.Items[i].FieldClass.Create(self);
dmp.FieldName:=DataSet.FieldDefs.Items[i].DisplayName;
dmp.DataSet:=dataset;
if (dmp.fieldname='txtState') or (dmp.FieldName='txtOldState') then
begin
dmp.Calculated:=true;
dmp.DisplayWidth:=255;
dmp.size:=255;
end;
end;
dataset.active:=true;
finally
initing:=false;
end;
end;
procedure TSampleForm.dsSampleAfterClose(
DataSet: TDataSet);
var
i:integer;
dmp:TField;
begin
if not initing then
begin
for i:=DataSet.FieldCount-1 downto 0 do
begin
dmp:=pointer(DataSet.Fields.Fields[i]);
DataSet.Fields.Fields[i].DataSet:=nil;
freeandnil(dmp);
end;
DataSet.FieldDefs.Clear;
end;
end;
procedure TSampleForm.dsSampleCalcFields(
DataSet: TDataSet);
var
tmpdurum,tmpOldDurum:integer;
begin
if not initing then
begin
tmpDurum := dataset.FieldByName( 'state' ).AsInteger;
tmpOldDurum:= dataset.FieldByName( 'oldstate' ).AsInteger;
dataset.FieldByName( 'txtState' ).AsString := State2Text(tmpDurum);
dataset.FieldByName( 'txtOldState' ).AsString := State2Text(tmpOldDurum);
end;
end;
procedure TSampleForm.btnOpenClick(Sender: TObject);
begin
if dsSample.Active then
dsSample.Close;
dsSample.SQL.text:='select id,state,oldstate,"" as txtState,"" as txtOldState from states where active=1';
dsSample.Open;
end;