Recent

Author Topic: Lookup fields do not return data.  (Read 31993 times)

taazz

  • Hero Member
  • *****
  • Posts: 5368
Lookup fields do not return data.
« on: September 11, 2012, 11:22:21 am »
Any one else having problems with fklookup fields?

Having create one and place it in a DBGrid does not show any data.

I'm attaching a demo project. It requires firebird and connect it to the employe database before activating the connection and the queries.

Thank you for any hints.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

ludob

  • Hero Member
  • *****
  • Posts: 1173
Re: Lookup fields do not return data.
« Reply #1 on: September 11, 2012, 01:58:47 pm »
2 problems:
- set stringfield1.LookupCache to True. If not using the LookupCache then TField.CalcLookupValue uses FLookupDataSet.Lookup which is not implemented in TBufDataset. fpc 2.7.1 has it implemented but it causes other problems in this case.
- remove stringfield1.OnGetText. Commenting the contents out still makes that OnGetText is called and the result is always an empty string.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Lookup fields do not return data.
« Reply #2 on: September 11, 2012, 02:40:58 pm »
2 problems:
- set stringfield1.LookupCache to True. If not using the LookupCache then TField.CalcLookupValue uses FLookupDataSet.Lookup which is not implemented in TBufDataset. fpc 2.7.1 has it implemented but it causes other problems in this case.

OK. although I would like to know where exactly is the code that decides to call the CalcLookupValue I've be trying to find almost all day to day (on and off).

- remove stringfield1.OnGetText. Commenting the contents out still makes that OnGetText is called and the result is always an empty string.

Yeah that one I found it also, it makes no sense though if there is an event handler then do not run the required code policy seems more like a hack to speed things up instead of a rock solid behavior.

Oh well any shortcomings that I should be aware of ? eg refreshing the lookupdataset would require an explicit refresh of the dblookupfield cache?

thank you for your time greatly appreciated.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

ludob

  • Hero Member
  • *****
  • Posts: 1173
Re: Lookup fields do not return data.
« Reply #3 on: September 11, 2012, 03:28:52 pm »
Quote
OK. although I would like to know where exactly is the code that decides to call the CalcLookupValue I've be trying to find almost all day to day (on and off).
Stack trace when entering a value in SQLQuery1HEAD_DEPT:
Code: [Select]
#0 TFIELD__CALCLOOKUPVALUE(<error reading variable>) at .\fcl-db\src\base\fields.inc:617
#1 TDATASET__CALCULATEFIELDS(0x97508 '', <error reading variable>) at .\fcl-db\src\base\dataset.inc:150
#2 TDATASET__GETCALCFIELDS(0x26df8c0 #168#248'm'#2#204#250'm'#2#1, <error reading variable>) at .\fcl-db\src\base\dataset.inc:472
#3 TDATASET__EDIT(<error reading variable>) at .\fcl-db\src\base\dataset.inc:1698
#4 TDATASET__INTERNALCANCEL(<error reading variable>) at .\fcl-db\src\base\dataset.inc:934
#5 ?? at :0
#6 TCUSTOMGRID__EDITORKEYPRESS(0xa1a38, 49 '1', <error reading variable>) at grids.pas:7598
TField.CalcLookupValue is where LookupCache is tested.

Quote
Yeah that one I found it also, it makes no sense though if there is an event handler then do not run the required code policy seems more like a hack to speed things up instead of a rock solid behavior.
What do you suggest? That aText should contain the string value as it would be displayed without the handler? The current behavior is in lin with many event handlers. Assign an TDBGrid.OnDrawColumnCell or a TForm.OnPaint and enter no code: nothing will be drawn.
Quote
eg refreshing the lookupdataset would require an explicit refresh of the dblookupfield cache?
Yep. By calling StringField1.RefreshLookupList;

Another known messy situation is that the lookupdataset is set active when the binding is done between field and lookupdataset. This causes some spurious activation of datasets when the form is streamed. Some bugreports and forum threads discuss this behavior.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Lookup fields do not return data.
« Reply #4 on: September 11, 2012, 04:23:25 pm »

Stack trace when entering a value in SQLQuery1HEAD_DEPT:
Code: [Select]
#0 TFIELD__CALCLOOKUPVALUE(<error reading variable>) at .\fcl-db\src\base\fields.inc:617
#1 TDATASET__CALCULATEFIELDS(0x97508 '', <error reading variable>) at .\fcl-db\src\base\dataset.inc:150
#2 TDATASET__GETCALCFIELDS(0x26df8c0 #168#248'm'#2#204#250'm'#2#1, <error reading variable>) at .\fcl-db\src\base\dataset.inc:472
#3 TDATASET__EDIT(<error reading variable>) at .\fcl-db\src\base\dataset.inc:1698
#4 TDATASET__INTERNALCANCEL(<error reading variable>) at .\fcl-db\src\base\dataset.inc:934
#5 ?? at :0
#6 TCUSTOMGRID__EDITORKEYPRESS(0xa1a38, 49 '1', <error reading variable>) at grids.pas:7598
TField.CalcLookupValue is where LookupCache is tested.

What do you suggest? That aText should contain the string value as it would be displayed without the handler?

Code: [Select]
function TField.GetDisplayText: String;
begin
  ///SetLength(Result, 0);
  GetText(Result, True);
  if Assigned(OnGetText) then
    OnGetText(Self, Result, True);
end;       

The current behavior is in line with many event handlers.
Assign an TDBGrid.OnDrawColumnCell or a TForm.OnPaint and enter no code: nothing will be drawn.

although I disagree with this behavior it is understandable up to a point. Windows solved this problem by allowing the callback procedure to flag the message handled so it does not paint anything if it is flagged or paint everything if it is not, but this is not comparable to the problem at hand a draw procedure has many levels and  can't be broken down to smaller steps (this is a design flow in my view btw) so it is understandable to have an all or nothing policy including call the callback before the default paint, to avoid screen flicker and speed up the application responsiveness. Of course the paint is called a few dozen times a second and is a lot slower than a simple move/convert of a few bytes overall so it makes sense to cut off the old for the sake of the new.

On data events on the other hand (especially on bufdataset which already has the data in  memory) it is a design flow not to pass that data to the user's event.There is no all or nothing and most of the times some kind of check on the existing data would be required.

As it is now we have created a dangerous re-entrance situation think of it like this the user writes the event checks the text variable sees nothing and calls the displaytext property to get the text. That of course forces its application in to a loop which eventually will eat up all his stack and raise an exception.

This simple change will probably avoid most problems but hey you know what Einstein said about stupidity and the universe no guaranties can be made other than actively guarding against the re-entrance.

I hope I made my self clear of what I mean speed hack instead of stable I didn't mean to say that the framework is not stable.

Yep. By calling StringField1.RefreshLookupList;
Noted for future reference. I'm going to check for a more generic method first though and I'll report back.

Another known messy situation is that the lookupdataset is set active when the binding is done between field and lookupdataset. This causes some spurious activation of datasets when the form is streamed. Some bugreports and forum threads discuss this behavior.

Oh right I think I remember one of those it was resent as well.
Noted. first open the lookup datasets then link them to the lookup fields.

The good think is that everything is dynamic in my application even field definition and creation so I can just move a line of code or two up a few steps and this is no issue.

Thank you for your time as always you have been most helpful.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

ludob

  • Hero Member
  • *****
  • Posts: 1173
Re: Lookup fields do not return data.
« Reply #5 on: September 11, 2012, 05:06:42 pm »
Quote
On data events on the other hand (especially on bufdataset which already has the data in  memory) it is a design flow not to pass that data to the user's event.
OnGetText has Sender: TField as the first parameter. So the user has direct access to the field in memory.
Quote
As it is now we have created a dangerous re-entrance situation think of it like this the user writes the event checks the text variable sees nothing and calls the displaytext property to get the text. That of course forces its application in to a loop which eventually will eat up all his stack and raise an exception.

This simple change will probably avoid most problems but hey you know what Einstein said about stupidity and the universe no guaranties can be made other than actively guarding against the re-entrance.
http://www.freepascal.org/docs-html/fcl/db/tfield.ongettext.html:
Quote
OnGetText is triggered whenever the TField.Text or TField.DisplayText properties are read.
Users accessing TField.DisplayText in TField.OnGetText deserve to be punished  8-)

codifies

  • Jr. Member
  • **
  • Posts: 98
    • bedroomcoders
Re: Lookup fields do not return data.
« Reply #6 on: September 13, 2012, 01:19:36 pm »
I'm having this issue with dbgrid the drop down happens with the correct contents but nothing is displayed in the cell

in
DBGrid1DrawColumnCell

column.field.asstring is always blank

I've turned lookup cache on anything else I need to do?
Lazarus 2.3.0 r3945f73 FPC 3.2.0 x86_64-linux-gtk2

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Lookup fields do not return data.
« Reply #7 on: September 13, 2012, 01:51:12 pm »
As far as I know no there is nothing else you need to do. But be very careful do not use the fields lookupdataset for anything else, the code for lookup needs a lot of work it opens and closes the lookupdataset on demand it assumes to much and its generally not advised to have any other components than the lookup field depend on it.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

ludob

  • Hero Member
  • *****
  • Posts: 1173
Re: Lookup fields do not return data.
« Reply #8 on: September 13, 2012, 01:52:19 pm »
Is your keyfields for the fpLookup field set to the correct field? If the dropdown lists the correct values but column.field.asstring always returns '' then probably you are looking up the wrong value.


codifies

  • Jr. Member
  • **
  • Posts: 98
    • bedroomcoders
Re: Lookup fields do not return data.
« Reply #9 on: September 13, 2012, 06:23:31 pm »
I couldn't say it now says can't do operation on a none active data set when it runs
(doesn't say which one and they are both active...)

I'll have to start from scratch, but its obvious I'm not understanding something as it all seems very fragile and easy to break inadvertently - which is a real shame as I can see how flexible it has the potential to be and how much work must have gone into it...

Lazarus 2.3.0 r3945f73 FPC 3.2.0 x86_64-linux-gtk2

Knipfty

  • Full Member
  • ***
  • Posts: 232
Re: Lookup fields do not return data.
« Reply #10 on: September 13, 2012, 06:27:32 pm »
chris_c,

post the code from the .lfr file.  In it will be the settings you are using in the IDE.
64-bit Lazarus 2.2.0 FPC 3.2.2, 64-bit Win 11

codifies

  • Jr. Member
  • **
  • Posts: 98
    • bedroomcoders
Re: Lookup fields do not return data.
« Reply #11 on: September 13, 2012, 08:35:59 pm »
thanks but I scrapped it in the end...
Lazarus 2.3.0 r3945f73 FPC 3.2.0 x86_64-linux-gtk2

codifies

  • Jr. Member
  • **
  • Posts: 98
    • bedroomcoders
Re: Lookup fields do not return data.
« Reply #12 on: September 13, 2012, 11:49:15 pm »
i must be a sucker for punishment I started from scratch and can't even get as far as I got before...

no doubt something daft, I cant help but think if the look up field settings were populated with valid entries for that property, people would have a lot less problems!


did you mean this file
Code: [Select]
object Form1: TForm1
  Left = 400
  Height = 360
  Top = 254
  Width = 658
  Caption = 'Form1'
  ClientHeight = 360
  ClientWidth = 658
  LCLVersion = '1.0.1.3'
  object DBGrid1: TDBGrid
    Left = 36
    Height = 214
    Top = 106
    Width = 576
    AutoFillColumns = True
    Color = clWindow
    Columns = <>
    DataSource = peopleDatasource
    TabOrder = 0
  end
  object MySQL51Connection1: TMySQL51Connection
    Connected = True
    LoginPrompt = False
    DatabaseName = 'mydb'
    KeepConnection = False
    Password = 'db123'
    Transaction = SQLTransaction1
    UserName = 'dbuser'
    HostName = 'localhost'
    LogEvents = []
    left = 88
    top = 16
  end
  object SQLTransaction1: TSQLTransaction
    Active = False
    Action = caNone
    Database = MySQL51Connection1
    left = 248
    top = 16
  end
  object peopleQuery: TSQLQuery
    IndexName = 'DEFAULT_ORDER'
    FieldDefs = <   
      item
        Name = 'peopleid'
        DataType = ftInteger
        Precision = -1
        Size = 0
      end   
      item
        Name = 'fktitleid'
        DataType = ftInteger
        Precision = -1
        Size = 0
      end   
      item
        Name = 'surname'
        DataType = ftString
        Precision = -1
        Size = 45
      end   
      item
        Name = 'forename'
        DataType = ftString
        Precision = -1
        Size = 45
      end   
      item
        Name = 'address'
        DataType = ftMemo
        Precision = -1
        Size = 0
      end>
    Active = True
    Database = MySQL51Connection1
    Transaction = SQLTransaction1
    SQL.Strings = (
      'select * from people;'
    )
    Params = <>
    left = 376
    top = 16
    object peopleQuerypeopleid: TLongintField
      DisplayWidth = 10
      FieldKind = fkData
      FieldName = 'peopleid'
      Index = 0
      LookupCache = False
      ProviderFlags = [pfInUpdate, pfInWhere]
      ReadOnly = False
      Required = False
      Visible = False
      OnChange = peopleQuerypeopleidChange
    end
    object peopleQueryfktitleid: TLongintField
      DisplayWidth = 10
      FieldKind = fkLookup
      FieldName = 'fktitleid'
      Index = 1
      KeyFields = 'fktitleid'
      LookupCache = True
      LookupDataSet = titleQuery
      LookupKeyFields = 'titleid'
      LookupResultField = 'title'
      ProviderFlags = [pfInUpdate, pfInWhere]
      ReadOnly = False
      Required = False
    end
    object peopleQueryforename: TStringField
      DisplayWidth = 45
      FieldKind = fkData
      FieldName = 'forename'
      Index = 2
      LookupCache = False
      ProviderFlags = [pfInUpdate, pfInWhere]
      ReadOnly = False
      Required = False
      Size = 45
    end
    object peopleQuerysurname: TStringField
      DisplayWidth = 45
      FieldKind = fkData
      FieldName = 'surname'
      Index = 3
      LookupCache = False
      ProviderFlags = [pfInUpdate, pfInWhere]
      ReadOnly = False
      Required = False
      Size = 45
    end
    object peopleQueryaddress: TMemoField
      DisplayWidth = 10
      FieldKind = fkData
      FieldName = 'address'
      Index = 4
      LookupCache = False
      ProviderFlags = [pfInUpdate, pfInWhere]
      ReadOnly = False
      Required = False
      BlobType = ftBlob
      Transliterate = False
    end
  end
  object titleQuery: TSQLQuery
    IndexName = 'DEFAULT_ORDER'
    FieldDefs = <>
    Database = MySQL51Connection1
    Transaction = SQLTransaction1
    SQL.Strings = (
      'select * from titles;'
    )
    Params = <>
    left = 483
    top = 16
  end
  object peopleDatasource: TDatasource
    DataSet = peopleQuery
    left = 584
    top = 16
  end
  object titleDatasource: TDatasource
    DataSet = titleQuery
    left = 111
    top = 82
  end
end

Lazarus 2.3.0 r3945f73 FPC 3.2.0 x86_64-linux-gtk2

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Lookup fields do not return data.
« Reply #13 on: September 14, 2012, 12:45:46 am »
Careful now, you need to have both the titleID and titleID lookup field you can't select fktitleid as the key field you need an field with fieldkind = fkData in the KeyFields property.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

codifies

  • Jr. Member
  • **
  • Posts: 98
    • bedroomcoders
Re: Lookup fields do not return data.
« Reply #14 on: September 14, 2012, 02:57:57 am »
not sure what you meant there please bare in mind what you see there is the product of me trying just about every combination I could think of and failing to understand the feedback from Lazarus.

people table has

peopleid <- AI PK
fktitleid <- foreign key to titles.titleid
other fields

titles table

titleid <- AI PK
title <- string to display instead of foreign key way displaying a person record

Lazarus 2.3.0 r3945f73 FPC 3.2.0 x86_64-linux-gtk2

 

TinyPortal © 2005-2018