0

I have a class which should contain datafields like TIntegerField, TFloatField, ... In an Init-Function I want to open a dataset to get the right datarecord from DB and put the values to the fields in the classinstance. Because I don't want to write down all the fields of the class I want do this dynamicly with rtti. I wonder how I can create an instance e.g. of a TFLoatfield and copy the FloatField from dataset to classfield. My function finds the floatfiled but I cannot create the Instance and copy the value.

var
  rttiContext: TRttiContext;
  rttiType: TRttiType;
  attribute: TCustomAttribute;
  rttiField: TRttiField;
begin
  myQuery.Close;
  myQuery.SQL.Clear;
  myQuery.SQL.Add('SELECT * FROM prices');
  myQuery.SQL.Add('WHERE ID=' + IntToStr(FID));
  myQuery.Open();
  try
    rttiContext := TRttiContext.Create;
    try
      rttiType := rttiContext.GetType(TPrice);
      for rttiField in rttiType.GetFields do
      begin
        if rttiField.FieldType.ToString = 'TFloatField' then
        begin
          // create Instance of Floatfield does not work!
          if not assigned(TFloatField(rttiType.GetField(rttiField.Name))) then
            TFloatField(rttiType.GetField(rttiField.Name)).Create(nil);
          // Copy Floatfield from dataset to classfield does not work!
          TFloatField(rttiType.GetField(rttiField.Name)).Value := tmpQuery.FieldByName(rttiField.Name).Value;
        end;
      end;
    finally
      rttiContext.Free;
    end
  finally
    myQuery.Close;
  end;
end; 
Rudi77
  • 11
  • 1
  • Ok, but what is your question? And why don't you just do what everyone normally does, i.e. either create persistent TFields, or just let the dataset create them dynamically when it is opened? – MartynA Apr 06 '17 at 09:09
  • what do you mean with persistent TFields? I want to map tables in classes. – Rudi77 Apr 06 '17 at 09:20
  • Right-click the dataset in the IDE, select Fields Editor and then use the menu to create the fields from the dataset. Fields created that way "persist" because they are created on the form/datamodule. – MartynA Apr 06 '17 at 09:24
  • Ahh ok the normal way :) but I want for each table a class. So I can open it with mytable := TCostumer.create(1) to get the record with ID=1. – Rudi77 Apr 06 '17 at 09:48
  • Then I think you'd better read my answer. There's certainly nothing stopping you creating a customised dataset, but you need to understand what you can and can't do, in terms of creating and using TFields. – MartynA Apr 06 '17 at 09:56

1 Answers1

0

Your comment

Copy Floatfield from dataset to classfield does not work!

is correct, TFields only work when they are associated with a TDataSet; they cannot work in isolation from one because they use the record buffers set up by the dataset to hold the data they operate on.

create Instance of Floatfield does not work!

Wrong. You can create an instance of TFloatField by whatever method you like, e.g.

var FloatField : TFloatField;

  FloatField := TFloatField.Create(Self);  //  self being e.g. TForm1 or DataModule1
  FloatField.FieldName := 'AFloatField';
  FloatField.FieldKind := fkData;
FloatField.DataSet := myQuery;
  [etc]

but I think the point that you have missed is that you can only do this successfully before the dataset is opened. Once the dataset is open it is too late because in the absence of persistent fields, the dataset will create dynamically a set of default fields which only live as long as the dataset is open.

"Persistent" Fields are so called because they are stored in the DFM of the form or DataModule in which they are created using the Fields Editor you can access using the context menu of the dataset in the IDE.

Btw, many people have using Attribute annotations for classes to create customised datasets. One good article on it is here:

http://francois-piette.blogspot.co.uk/2013/01/using-custom-attribute-for-data.html

You might also want to take a look at the Spring4D library, which might save you a lot of work. See e.g. https://spring4d.4delphi.com/docs/develop/Html/index.htm?Spring.Persistence.Core.Base.TDriverResultSetAdapter(T).DataSet.htm as a way into it.

MartynA
  • 30,454
  • 4
  • 32
  • 73
  • >>"TFields only work when they are associated with a TDataSet" OK then I need own classes for my Integerfields, Floatfields, ... in my mappingclasses? But how can I create these objects in my Init-function with rtti? – Rudi77 Apr 06 '17 at 10:04
  • What are you asking by quoting that? – MartynA Apr 06 '17 at 10:06
  • thx for the Links. We already use thes classes to read from our DB but now we want to write an I have Problems with values that are NULL on DB. In my classes I have Integer, TDateTime, ... when I read from DB they get the Value 0 when they are NULL on DB. When I want to write them back I don't know if the ware NULL before or 0. – Rudi77 Apr 06 '17 at 10:14
  • That's a completely different point than what you asked in your q. The `.AsInteger`, `AsFloat`, etc getters for TField values return 0 when the field in the DB is actually NULL, but you can test for that in code using the `TField.IsNull` function. – MartynA Apr 06 '17 at 10:18
  • No, I mean at the moment I have no datafields in my classes. I use normal types like integer, double, ... This was ok as long I was only reading with my classes. Now I want to write to my Database and when eg my Integer value is 0 I don't know whether my value is 0 or NULL. – Rudi77 Apr 06 '17 at 10:30
  • Well, if you don't know, how will anyone else know? – MartynA Apr 06 '17 at 11:06
  • What I mean with "I don't know" is that now my class hast classfields like FID: Integer, FNr: Integer, FDate1: TDateTime, .... when I call my Initfunction these Fields were initialized with 0 and it doesn't matter whether the datafield ist Null or 0. – Rudi77 Apr 06 '17 at 12:02
  • Sorry, I really have no idea what you mean by "don't know" in that case. Anyway, this is really getting rather a long way from what your q asked. If you need help with what you are asking in these comments, I suggest you post a new SO question. – MartynA Apr 06 '17 at 12:04
  • OK I'll do that. Sorry this was my first one. Anyway thanks a lot! – Rudi77 Apr 06 '17 at 12:08
  • Btw, if you are relying on the user's input to define the values of a new record, you might take the pragmatic approach that unless and until the user specifies a value for a particular field, its value in the database should be NULL, using NULL in the sense of "unknown or unspecfied". So, if you are not going to use the standard gui db-aware controls, you need ones that are capable of handling nullable values. – MartynA Apr 06 '17 at 15:09