Board index » delphi » TTable/TQuery "Access violation ..." Problem

TTable/TQuery "Access violation ..." Problem

Help, I'm stuck with this problem!

I am displaying the results of a query and trying to
retrieve the current record.  This is the code, which is attached to
button.

Before I put in the
 "Active := True;"
I got a message -
 "Cannot perform this operation on a closed dataset"

Now I get the message -
 "Access violation at address 00000000. Read of address 00000000"

I've no idea what I've done wrong - this is my first shot at TQuery,
so it is probably something basic and horribly obvious to the rest
of the world!!  (Delphi 3, by the way and the tables are Paradox)
=================================================================
DM is my Datamodule
ATable is TTable
AQuery is a TQuery on ATable
'Code' is the Primary Key of ATable
AQuery is non-live since it includes to joins to two tables.
==================================================================
with DM.ATable
do begin
   try
      Filtered := False;
      Active := True;
      SetKey;
      FieldByName('Code').AsString :=
DM.AQuery.FieldByName('Code').AsString;
      GotoKey;
      Edit;
   except
      MessageDlg('Record not available',mtWarning,[mbOK],0);
   end;
end;
=================================================================

Regards

Jeff

--
Jeff Cook                                         je...@aspect.co.nz
+---------------------------------------------------------------------------+

|At work:        Phone: +64-9-424 5388       Fax:    +64-21-785 097 |
|   Program Development/Client Support  Mobile: +64-21-635 185 |
|   Aspect Systems Ltd                                             |
|   Specialists in software for Real Estate and Human Resources    |
+------------------------------------------------------------------+
|At home:                                   Phone:  +64-9-424 0336 |
|   Husband, Dad, Grandad                                          |
|   Enthusiastic but slow triathlete                               |
|   Justice of the Peace                                           |
+------------------------------------------------------------------+

 

Re:TTable/TQuery "Access violation ..." Problem


Jeff:

Greetings! This sounds like a problem that I run into from time to time (in fact,
it just happened again yesterday). It sounds as if your TDataModule object is not
being created before you are attempting to set TTable.Active := True. Check the
Forms page of the Project Options dialog box (Project / Options... / Forms). Look
at the list of of forms in the Auto-Create Forms listbox. Are both your TForm and
your TDataModule listed there? Is your TDataModule listed there before your TForm
containing the call to the TTable? Technically, it probably should be. You can
drag and drop the forms in the list to change the creation order.

Where I run into this problem is that I don't usually allow Delphi to Auto-create
my forms for me except for the Main form, thereby cutting down on unnecessary
resource consumption. When I need a TForm or TDataModule, I create an instance of
it by calling its Create method. Therefore, in my Auto-Create Forms listbox, only
the Main form is listed. My TDataModule and other forms remain in the Available
Forms listbox. My problem occurs when I create a whole new TForm with controls
that make calls to controls in my TDataModule in the TForm.OnCreate event and
forget to remove the new TForm from the Auto-Create listbox. Delphi, by default,
sets all new forms as Auto-Create. Now I have a situation where my Main form and
new TForm are autocreated when the app starts, but my TDataModule has yet to be
created. This means the new TForm is making calls to a control in a TDataModule
that Delphi knows is a valid name (otherwise the compiler would have caught it)
but since the object has not yet been instantiated it causes an Access Violation
error.

If this is what is happening in your case, you need to do one of three things:

1. If you want to allow Delphi to Auto-create all your forms, make sure that both
are in the Auto-Create listbox with the TDataModule before the TForm that calls
it.

or

2. If you want to manually create all your TForms but Auto-Create the
TDataModule, put your Main form and your TDataModule in the Auto-Create listbox
and create the other ones as needed. This way you would be guaranteed that the
TDataModule would always exist when you needed it.

or

3. If you are going to manually create all of your forms yourself including the
TDataModule, make sure that you are manually creating the TDataModule before any
TForms that call it. Before creating your TForm, you could check to see if the
TDataModule exists. The following code should work, where dmMyData is your
TDataModule:

if dmMyData = nil then       // i.e., has not been assigned to an instance of
TdmMyData
    dmMyData = TdmMyData.Create(self)    // creates an instance of TdmMyData

Now, since you created it, you will have to destroy it when you're finished with
it by calling its Free method.

Good Luck! I hope that this helps. Let me know.

Kevin
kjmey...@epix.net

Re:TTable/TQuery "Access violation ..." Problem


Thanks Kevin

I've printed out your message and will try your suggestions - yes - there are a "few"
holes in my knowledge from learning Delphi from the book and by just jumping in a
trying it out.

Jeff

Quote
Kevin Meyers wrote:
> Jeff:

> Greetings! This sounds like a problem that I run into from time to time (in fact,
> it just happened again yesterday). It sounds as if your TDataModule object is not
> being created before you are attempting to set TTable.Active := True. Check the
> Forms page of the Project Options dialog box (Project / Options... / Forms). Look
> at the list of of forms in the Auto-Create Forms listbox. Are both your TForm and
> your TDataModule listed there? Is your TDataModule listed there before your TForm
> containing the call to the TTable? Technically, it probably should be. You can
> drag and drop the forms in the list to change the creation order.

> Where I run into this problem is that I don't usually allow Delphi to Auto-create
> my forms for me except for the Main form, thereby cutting down on unnecessary
> resource consumption. When I need a TForm or TDataModule, I create an instance of
> it by calling its Create method. Therefore, in my Auto-Create Forms listbox, only
> the Main form is listed. My TDataModule and other forms remain in the Available
> Forms listbox. My problem occurs when I create a whole new TForm with controls
> that make calls to controls in my TDataModule in the TForm.OnCreate event and
> forget to remove the new TForm from the Auto-Create listbox. Delphi, by default,
> sets all new forms as Auto-Create. Now I have a situation where my Main form and
> new TForm are autocreated when the app starts, but my TDataModule has yet to be
> created. This means the new TForm is making calls to a control in a TDataModule
> that Delphi knows is a valid name (otherwise the compiler would have caught it)
> but since the object has not yet been instantiated it causes an Access Violation
> error.

> If this is what is happening in your case, you need to do one of three things:

> 1. If you want to allow Delphi to Auto-create all your forms, make sure that both
> are in the Auto-Create listbox with the TDataModule before the TForm that calls
> it.

> or

> 2. If you want to manually create all your TForms but Auto-Create the
> TDataModule, put your Main form and your TDataModule in the Auto-Create listbox
> and create the other ones as needed. This way you would be guaranteed that the
> TDataModule would always exist when you needed it.

> or

> 3. If you are going to manually create all of your forms yourself including the
> TDataModule, make sure that you are manually creating the TDataModule before any
> TForms that call it. Before creating your TForm, you could check to see if the
> TDataModule exists. The following code should work, where dmMyData is your
> TDataModule:

> if dmMyData = nil then       // i.e., has not been assigned to an instance of
> TdmMyData
>     dmMyData = TdmMyData.Create(self)    // creates an instance of TdmMyData

> Now, since you created it, you will have to destroy it when you're finished with
> it by calling its Free method.

> Good Luck! I hope that this helps. Let me know.

> Kevin
> kjmey...@epix.net

--
Jeff Cook                                         je...@aspect.co.nz
+------------------------------------------------------------------+
|At work:        Phone: +64-9-424 5388      Fax:    +64-21-785 097 |
|   Program Development/Client Support      Mobile: +64-21-635 185 |
|   Aspect Systems Ltd                                             |
|   Specialists in software for Real Estate and Human Resources    |
+------------------------------------------------------------------+
|At home:                                   Phone:  +64-9-424 0336 |
|   Husband, Dad, Grandad                                          |
|   Enthusiastic but slow triathlete                               |
|   Justice of the Peace                                           |
+------------------------------------------------------------------+

Re:TTable/TQuery "Access violation ..." Problem


Hi, I'm still struggling with this problem!

Kevin Meyers gave me some good advice about eliminating the auto-creates
that Delphi does for you.  I had 23 forms being created at start up and
have reduced this to just two - the main form and the data module. As the
project will have in excess of 100 forms when complete, this was timely
advice for me.  No wonder it took so long to bring up the first screen!

I now understand a bit better the relationships between modules but I still
get my "Access violation ... " message, though it now has actual addresses
instead of "00000000".  Debugging the code, I find that the error occurs
on the "GotoKey" statement, so presumably my program knows about the data
module - which was created at start up and not freed anywhere.

The code now looks like this.
=================================================================
DM is my Datamodule
ATable is TTable
AQuery is a TQuery on ATable
'Code' is the Primary Key of ATable
AQuery is non-live since it includes to joins to two tables.
==================================================================
procedure TAAAA.NavEditClick(Sender: TObject);
var RecordKey : string;
begin
 RecordKey := DM.AQuery.FieldByName('Code').AsString;
 with DM.ATable
 do begin
     try
        Open;
   SetKey;
        FieldByName('Code').AsString := RecordKey;
        GotoKey;
        Edit;
     except
        MessageDlg('Record not available for Code '+RecordKey,
       mtWarning,[mbOK],0);
     end;
 end;
end;
=================================================================

There is also an interesting thing happening to two DBLookupComboBox's
on the form.  Both point to fields in the query.  Before the error both
appear to work correctly in that you can click on the little arrow and
a drop down box appears with the values that are in the records.
After the error has occured, one box works still, but the other gives
me an "Access violation ..." just like the code above.  The one that
works points to the field that is the primary key of the underlying
table, the one that does points to the secondary key. Is this a clue?

Regards

Jeff

Quote
Kevin Meyers wrote:
> Jeff:

> Greetings! This sounds like a problem that I run into from time to time (in fact,
> it just happened again yesterday). It sounds as if your TDataModule object is not
> being created before you are attempting to set TTable.Active := True. Check the
> Forms page of the Project Options dialog box (Project / Options... / Forms). Look
> at the list of of forms in the Auto-Create Forms listbox. Are both your TForm and
> your TDataModule listed there? Is your TDataModule listed there before your TForm
> containing the call to the TTable? Technically, it probably should be. You can
> drag and drop the forms in the list to change the creation order.

> Where I run into this problem is that I don't usually allow Delphi to Auto-create
> my forms for me except for the Main form, thereby cutting down on unnecessary
> resource consumption. When I need a TForm or TDataModule, I create an instance of
> it by calling its Create method. Therefore, in my Auto-Create Forms listbox, only
> the Main form is listed. My TDataModule and other forms remain in the Available
> Forms listbox. My problem occurs when I create a whole new TForm with controls
> that make calls to controls in my TDataModule in the TForm.OnCreate event and
> forget to remove the new TForm from the Auto-Create listbox. Delphi, by default,
> sets all new forms as Auto-Create. Now I have a situation where my Main form and
> new TForm are autocreated when the app starts, but my TDataModule has yet to be
> created. This means the new TForm is making calls to a control in a TDataModule
> that Delphi knows is a valid name (otherwise the compiler would have caught it)
> but since the object has not yet been instantiated it causes an Access Violation
> error.

> If this is what is happening in your case, you need to do one of three things:

> 1. If you want to allow Delphi to Auto-create all your forms, make sure that both
> are in the Auto-Create listbox with the TDataModule before the TForm that calls
> it.

> or

> 2. If you want to manually create all your TForms but Auto-Create the
> TDataModule, put your Main form and your TDataModule in the Auto-Create listbox
> and create the other ones as needed. This way you would be guaranteed that the
> TDataModule would always exist when you needed it.

> or

> 3. If you are going to manually create all of your forms yourself including the
> TDataModule, make sure that you are manually creating the TDataModule before any
> TForms that call it. Before creating your TForm, you could check to see if the
> TDataModule exists. The following code should work, where dmMyData is your
> TDataModule:

> if dmMyData = nil then       // i.e., has not been assigned to an instance of
> TdmMyData
>     dmMyData = TdmMyData.Create(self)    // creates an instance of TdmMyData

> Now, since you created it, you will have to destroy it when you're finished with
> it by calling its Free method.

> Good Luck! I hope that this helps. Let me know.

> Kevin
> kjmey...@epix.net

--
Jeff Cook                                         je...@aspect.co.nz
+------------------------------------------------------------------+
|At work:        Phone: +64-9-424 5388      Fax:    +64-21-785 097 |
|   Program Development/Client Support      Mobile: +64-21-635 185 |
|   Aspect Systems Ltd                                             |
|   Specialists in software for Real Estate and Human Resources    |
+------------------------------------------------------------------+
|At home:                                   Phone:  +64-9-424 0336 |
|   Husband, Dad, Grandad                                          |
|   Enthusiastic but slow triathlete                               |
|   Justice of the Peace                                           |
+------------------------------------------------------------------+

Re:TTable/TQuery "Access violation ..." Problem


Jeff:

Well, I have some good news and I have some bad news:

The good news is: Your code works fine on my computer.

The bad news is: Your code works fine on my computer. Therefore, there's something else
we're missing.

A few things to double-check:

First, in your message, you stated that "AQuery is a TQuery on ATable". This would mean
literally that AQuery queries the <<component>> ATable. Are you really attempting to
access ATable through AQuery, or did you mean that AQuery and ATable both get their
data from the underlying table associated with ATable? It should be the latter. I'm not
trying to be picky about semantics, I just want to make sure that I am understanding
exactly what you are trying to do.

Second, is the AQuery.DataSource property set to nil (i.e., blank in the Object
Inspector)? It should be nil. This is a confusing property and in my opinion badly
named by Borland. It leads you to think that this is where you tell the TQuery to look
for finding the result set much like the DataSource property in a TDBGrid. But this is
not the case. I'll leave it to the Delphi on-line help to explain what it really does.
Suffice it to say that in most cases, the TQuery.DataSource property is nil. You
specify which tables to access through the TQuery.SQL property.

Third, make sure that your TTable, TQuery, and TDataModule objects are indeed all open
when the GotoKey statement is called, since that is where you are having trouble. You
can do this by putting each in the Watch Window and stepping through your code while
watching their values. If the value goes to nil, then the object has been freed which
still sound like your problem (i.e., you don't have a valid instantiated TTable).

Good luck and keep me posted. I'll let you know if I come up with anything. You might
try creating a new project with just the TDataModule, TQuery, and TTable and see if
that works. That's what I did. If it does, then look for what is different between the
two projects. I also used a form with a TDBNavigator and two TDBGrids -- one for the
TQuery and one for the TTable to see if the GotoKey was actually making it go to the
correct record. You will of course need to add two TDataSources to your TDataModule and
link one to your TTable and one to your TQuery since the TDBGrids can access to the
table and query through TDataSource componenets.

Again, keep me posted.

Kevin
kjmey...@epix.net

Other Threads