إضافة حقل محسوب إلى استعلام في وقت التشغيل

StackOverflow https://stackoverflow.com/questions/2523697

  •  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;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top