Inserting data into a database in delphi Xe8

0

The project I am working on requires a Sign Up form that needs to insert the User details into the database table.

The problem is that when the Sign Up Button is clicked the data entered into the edits doesn't save or update into the database. I also get an Access Violation "access violation at 0x0065e3e9 read of address 0x0000006c", and my code breaks at "tblUsers.Insert".

I have already tested my code and I have went through each line of code using Breaks to get to the source of the problem and I have found it to be the following portion of code.

with dmSM do
  begin
    tblUsers.Insert;
    tblUsers['FirstName'] := edtFirstName.Text;
    tblUsers['LastName'] := edtLastName.Text;
    tblUsers['BirthDate'] := cmbDay.Text + ' ' + cmbMonth.Text + ' ' +
                             cmbYear.Text;
    tblUsers['Gender'] := cmbGender.Text;
    tblUsers['AccountName'] := edtAccountName.Text;
    tblUsers['Password'] := edtPassword.Text;
    tblUsers.Post;
end; //end of with

I will try another method but it will be helpful if I can get some help with this.

Thank you in advance

Dominique

database
delphi
ms-access
insert
delphi-xe8
asked on Stack Overflow Aug 12, 2015 by Dominique Botha • edited Aug 12, 2015 by Dominique Botha

1 Answer

1

I am putting this answer up for the sake of completeness and for the benefit of future readers.

In your situation, the first thing to do would be to put a breakpoint on btlUsers.Insert. This will confirm that execution reaches that point and the exception occurs when that line executes.

Why the exception? There is a clue in the part of the message which says "read of address 0x0000006c". In Delphi a Nil pointer is effectively 0x00000000, and 6c is a small number (108 in decimal), and that's the clue, the debugger is telling you that the exception occurred a small offset from 0x00000000.

It's a characteristic of compiled Delphi code that the address of a member such as a data field of an object is at some fixed (and usually fairly small, unless the class in question is very large) offset from the base address of the object.

In you case, the 6c offset is from 0x00000000, so, a plausible explanation is that your code has tried to read a member of an object which is actually Nil.

So, at the breakpoint, evaluate dmSM and tblUsers. The debugger tells you that dmSM is Nil and that tblUsers isn't accessible, and it isn't accessible because dmSM is Nil. Why is dmSM Nil?

Most likely because it's a variable that references an object that hasn't been created by the time the breakpoint is reached. So:

Go to the Project Manager, right-click your executable in it and select Options. The Forms entry in the tree on the left will tell you which of your forms/datamodules have auto-created variables associated with them and the order in which they are created.

Then, look in the .Dpr file. It should look much like this:

begin
  Application.Initialize;
  Application.CreateForm(TDataModule1, DataModule1);
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

and if it's missing the line that creates the datamodule or it comes after the one that creates the form, that's your problem and it's trivial to fix.

However, sometimes, everything seems to be ok in the .Dpr file but the exception still occurs. @JerryDodge raised this point and it's a good one. What happens is that (usually due to an editing mistake), you duplicate the declaration of one of your auto-created objects. So now, for instance, you have two dmSMs declared, one in the unit where TdmSM is defined, and the duplicate somewhere else which the compiler sees in the compilation process after the one in your datamodule's unit. And because it's seen the duplicate more recently when it compiles the unit where the exception occurs, it assumes that your code is referring to the duplicate, not the original.

The reason I've tried to answer this q in such grinding detail is to make the point that a lot of the debugging process is thinking through the clues you get from carefully observing (and reporting, in an SO q) the behaviour of your errant program.

Finally, avoid using "with". Although it may save you a bit of typing, in the long run it tends to cause more trouble than it's worth. In your form unit, if you need to have to keep referring to some object in the datamodule, either assign its value to a variable scoped locally to the procedure in the form where you're doing it, or (better) define a function which returns the object in question, like so

function TForm1.tblUsers : TDataSet;
begin
  Result := dmSM.tblUsers;
end;
answered on Stack Overflow Aug 13, 2015 by MartynA • edited Aug 13, 2015 by MartynA

User contributions licensed under CC BY-SA 3.0