2

I guess I must be dense, I'm new to Delphi and am trying to read a sql result into a class to access it easily. I have created a dummy class to test like this:

type
test_class = class
 id:integer;
 job_number:string;
 cust_name :string ;
 procedure get_record_data;
end;

Then I call the procedure like this:

procedure test_class.get_record_data;
begin
 test_class.Create;
 test_class.id := tform3.adoQuery1.FieldByName('id').AsInteger;
 test_class.job_number := tform3.adoQuery1.FieldByName('job number').AsString;
 test_class.cust_name := tform3.adoQuery1.FieldByName('customer name').AsString;
end;

Then I test my result like this:

procedure TForm3.Button1Click(Sender: TObject);
begin
 showmessage('Id number is ' + inttostr(test_class.id));
end;

The showmessage line throws a compiler error that says Method Identifier Expected.

The lines that start with test_class.id:=, test_class.job_number:= and test_class.cust_name:= all give me the same Method Identifier Expected as well as a Missing Operator or semicolon error.

What am I doing wrong? Is there an easier way to go about this? Once I get this done, will null values present an issue?

2
  • 1
    I certainly won't use this as an answer, because it was written by me while I was still learning Delphi, and because this is a link to another website, but I wrote this a while back: tek-tips.com/faqs.cfm?fid=7420 Commented Aug 28, 2013 at 23:22
  • Also it doesn't directly solve your issue, but it's just an idea I was researching at one time. Commented Aug 28, 2013 at 23:34

3 Answers 3

8

You can not use a class as an instance. You will have to keep a reference to the created instance, according your example it could look like this ...

type
Ttest_class=class
 id:integer;
 job_number:string;
 cust_name :string ;
 Class Function get_record_data(ADS:TCustomAdodataset):Ttest_class;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  TC:Ttest_class;
begin
   TC := Ttest_class.get_record_data(AdoQuery1);
   try
   showmessage('Id number is ' + inttostr(TC.id));
   finally
     TC.Free
   end;
end;


class function Ttest_class.get_record_data(ADS: TCustomAdodataset): Ttest_class;
begin
 Result := Ttest_class.Create;
 Result.id:=ADS.FieldByName('id').AsInteger;
 Result.job_number:= ADS.FieldByName('job number').AsString;
 Result.cust_name:= ADS.FieldByName('customer name').AsString;
end;

As suggested by @MarjanVenema and requested by comment a preferable version:

type
  Ttest_class = class
    id: integer;
    job_number: string;
    cust_name: string;
    Constructor Create(ADS: TCustomAdodataset);
  end;

Constructor Ttest_class.Create(ADS: TCustomAdodataset);
begin
  id := ADS.FieldByName('id').AsInteger;
  job_number := ADS.FieldByName('job number').AsString;
  cust_name := ADS.FieldByName('customer name').AsString;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  TC: Ttest_class;
begin
  TC := Ttest_class.Create(ADOQuery1);
  try
    showmessage('Id number is ' + inttostr(TC.id));
  finally
    TC.Free
  end;
end;
Sign up to request clarification or add additional context in comments.

10 Comments

That works perfectly and will get me up and going with a lot better understanding. Thank you very much.
@bummi For a beginning Delphi programmer, wouldn't it be better to show him to create an instance rather then use class functions?
@JanDoggen I agree, I was picking up his approach, trying to show how to avoid hard references within the class. Since the way you mentioned is already shown in eKek0 answer changing my answer should not be necessary.
Why a class function instead of simply a constructor taking the ado dataset as a parameter? The class function's name also doesn't convey the fact that the caller takes ownership of lifetime management of what is returned.
OK, that makes perfect sense thank you very much for the help.
|
6

test_class is a type and not an instance variable. To access an object of type test_class you need to declare a variable of that type, create an instance and, just then, use its fields, properties of methods. Finally, you need to free the memory of that object.

For example (to not confuse you I won't use a try...finally):

procedure TForm3.Button1Click(Sender: TObject);
var tc: test_class;  //instance variable declaration
begin
  tc := test.class.Create; //creation of the object
  tc.get_record_data; //call a method to fill the class fields
  ShowMessage('Id number is ' + inttostr(tc.id)); //use of the object
  tc.Free; //freeing the memory object
end;

By the way, by convention the user defined types in Delphi begins with T and follows with camel case without underscores, as in TTestClass instead of test_class.

I guess that you don't know the concepts of classes, objects and instance variables. Google for their definitions, there is a lot of information about that, for example this tutorial.


In your get_record_data method if you want to fill the variables of the instance that they belongs, the thing will go like:

procedure test_class.get_record_data ;
begin
  id         := tform3.adoQuery1.FieldByName('id').AsInteger;
  job_number := tform3.adoQuery1.FieldByName('job number').AsString;
  cust_name  := tform3.adoQuery1.FieldByName('customer name').AsString;
end;

2 Comments

Ok, thanks. The Showmessage works, but the test_class.id:= and other lines that read the sql still don't work. Any suggestions for those lines?
Add a try finally and you'd get my vote. Call me weird but I like to see good practices being promoted.
1

Test_Class needs to know what it is populating it's data from. You are trying to refer to Form3.ADOQuery1, but TForm3 will almost definitely be the Class, not an object.

If you're using Delphi auto-generated code then there should be a line saying something like

var Form3: TForm3

at the top of your unit. If this is the case then you can correct your code by replacing all TForm3 with Form3 in that procedure.

A better solution is to give your get_record_data procedure the query it is to fill from:

procedure test_class.get_record_data (const aQuery: TADOQuery);
begin
  id         := aQuery.FieldByName('id').AsInteger;
  job_number := aQuery.FieldByName('job number').AsString;
  cust_name  := aQuery.FieldByName('customer name').AsString;
end;

Even better for such a small object is to pass in the 3 variables directly:

procedure test_class.set_object_data(const aID: integer; const aJob_Number, aCust_Name: string

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.