LocalMasterDetail did not work Correctly!!

Discussion of open issues, suggestions and bugs regarding ODAC (Oracle Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
ahijazi
Posts: 47
Joined: Mon 01 Oct 2007 11:13

LocalMasterDetail did not work Correctly!!

Post by ahijazi » Thu 29 Jul 2010 19:00

Dear DevArt;
After upgrade to ODAC 6.90.0.59 edition, a new issue raised in my applications, where I use LocalMasterDetail option I found the following:
1- Insert an new record in the Master table, without post;
2- Insert record in the Detail table, the record is inserted, but after post the detail record it become hidden ???
3- Post the mater record it will become visible again ????!!!

below a sample that demonstrate the issue, note that in ODAC 6.50.0.34 the issue are not exists ??!!!!!
Thanks in Advanced
Ahmed Hijazi P.Eng.

Code: Select all

var
  snConnection      : TOraSession;
  tblDepts, tblEmps : TOraTable;
  dsDepts           : TOraDataSource;

begin
  snConnection  := TOraSession.Create(self);
  tblDepts      := TOraTable.Create(self);
  tblEmps       := TOraTable.Create(self);
  dsDepts       := TOraDataSource.Create(self);



  with snConnection do begin
    Options.Direct := True;
    Username       := 'dblock';
    Password       := 'dblock';
    Server         := 'gisserver::gisdb';
    AutoCommit     := False;
    Connect;
    try
      ExecSQL('drop table Emps', []);
      ExecSQL('drop table Depts', []);
    except
    end;

    ExecSQL('create table DEPTS(OID NUMBER(8) not null, NAME VARCHAR2(50) not null, constraint TBLMASTER_PK primary key (OID))', []);
    ExecSQL('create table EMPS(OID NUMBER(8) not null, NAME VARCHAR2(50),DEPT_OID  NUMBER(8),constraint EMPS_PK primary key (OID), constraint EMPS_FK foreign key (DEPT_OID) references DEPTS (OID))', []);
  end;

  with tblDepts do begin
    TableName     := 'DEPTS';
    KeyFields     := 'OID';
    Session       := snConnection;
    CachedUpdates := True;
  end;

  dsDepts.DataSet := tblDepts;

  with tblEmps do begin
    TableName     := 'EMPS';
    MasterFields  := 'OID';
    DetailFields  := 'DEPT_OID';
    MasterSource  := dsDepts;
    KeyFields     := 'OID';
    Session       := snConnection;
    CachedUpdates := True;
    Options.LocalMasterDetail := True;
  end;


  tblDepts.open;
  tblEmps.Open;


  tblDepts.Insert;
  tblDepts.FieldByName('OID').Value  := 1;
  tblDepts.FieldByName('Name').Value := 'Dept A';

  // Note that I have not Post, in my case i need the Detail recod to be inserted first then Post the Master Record.

  with tblEmps do begin
    Append;
    FieldByName('OID').Value       := 1;
    FieldByName('Name').Value      := 'Emp A';
    FieldByName('Dept_OID').Value  := 1;
    Post;

    Append;
    FieldByName('OID').Value       := 2;
    FieldByName('Name').Value      := 'Emp B';
    FieldByName('Dept_OID').Value  := 1;
    Post;


    // Values will not appears ??, in the ODAC 6.50.0.34, it work fine, but in ODAC6.90.0.57 it's not !!!!!
    First;
    ShowMessage(FieldByName('Name').AsString); // Empty string displayed
    Next;
    ShowMessage(FieldByName('Name').AsString); // Empty string displayed


    // But after I execute the post of the master table is shown normaly !!!!! 
    tblDepts.Post;

    First;
    ShowMessage(FieldByName('Name').AsString); // "Emp A" displayed
    Next;
    ShowMessage(FieldByName('Name').AsString); // "Emp B" displayed
  end;

bork
Devart Team
Posts: 649
Joined: Fri 12 Mar 2010 07:55

Post by bork » Mon 02 Aug 2010 15:44

Hello

Thank you for the information. We have reproduced your issue. We will notify you as soon as we have any result.

bork
Devart Team
Posts: 649
Joined: Fri 12 Mar 2010 07:55

Post by bork » Thu 05 Aug 2010 14:52

Hello

You can use the RefreshParamsOnInsert variable to return old behavior. If you set the RefreshParamsOnInsert variable to True, then detail dataset will be refreshed before you post a new record. New behavior was added for improving performance and avoiding refreshing detail dataset on each master dataset field changing.

Now detail dataset is not refreshed if master dataset doesn't have any records. This is fixed and this fix will be included in the next ODAC build.

ahijazi
Posts: 47
Joined: Mon 01 Oct 2007 11:13

Post by ahijazi » Thu 05 Aug 2010 17:55

Dear Devart;

Can I make any workaround unitl your NextBuild ???

//
I modify the TCustomDADataSet.LocalDetailFilter little bit to fix this issue
as flow

Code: Select all

function TCustomDADataSet.LocalDetailFilter(RecBuf: IntPtr): boolean;
var
  DataSet: TDataSet;
  i: Integer;
begin
  Result := True;

  if FDataLink.DataSource  nil then begin
    DataSet := FDataLink.DataSource.DataSet;
    if (DataSet  nil) and DataSet.Active then begin
      // aHijazi: just add   --     or (DataSet.State in [dsInsert]) -- 
      Result :=  (DataSet.RecordCount  0) or (DataSet.State in [dsInsert]);
      if not Result then Exit;
    end;
  end;

  for i := 0 to Length(FLocalMDLinks) - 1 do
    with FLocalMDLinks[i] do begin
      if not Result then
        Break;
      if IsNull or TMemData(Data).GetNull(FieldNo, RecBuf) then
        Result := IsNull and TMemData(Data).GetNull(FieldNo, RecBuf)
      else
        Result := TMemData(Data).CompareFieldValue(Buffer, BufferType, Data.Fields[FieldNo - 1], RecBuf, []) = 0;
    end;
can I use this modified code till you release the Next Build

bork
Devart Team
Posts: 649
Joined: Fri 12 Mar 2010 07:55

Post by bork » Fri 06 Aug 2010 09:39

Hello

If you have ODAC with source code, then you can modify the TCustomDADataSet.LocalDetailFilter method:

Code: Select all

function TCustomDADataSet.LocalDetailFilter(RecBuf: IntPtr): boolean;
var
  DataSet: TDataSet;
  i: Integer;
begin
  Result := True;

  if FDataLink.DataSource  nil then begin
    DataSet := FDataLink.DataSource.DataSet;
    if (DataSet  nil) and DataSet.Active then begin
      // RefreshParamsOnInsert - returns old behavior
      Result := RefreshParamsOnInsert or (DataSet.RecordCount  0);
      if not Result then
        Exit;
    end;
  end;

  for i := 0 to Length(FLocalMDLinks) - 1 do
    with FLocalMDLinks[i] do begin
      if not Result then
        Break;
      if IsNull or TMemData(Data).GetNull(FieldNo, RecBuf) then
        Result := IsNull and TMemData(Data).GetNull(FieldNo, RecBuf)
      else
        Result := TMemData(Data).CompareFieldValue(Buffer, BufferType, Data.Fields[FieldNo - 1], RecBuf, []) = 0;
    end;
end;

Post Reply