Avatar billede rozh Nybegynder
22. maj 2004 - 17:08 Der er 1 kommentar og
1 løsning

Master/detail relation

Jeg har to komponenter, som jeg selv laver.
Den ene komponent, TRozhsMySQLDataSet er deriveret fra Scibits TMySQLDataSet, som kan downloades her:
http://www.scibit.com/products/mysqlcomponents/index.htm
Den anden, TRozhMySQLDataSource, er deriveret fra Delphis egen TDataSource.

Min TRozhsDataSet har en eneste ændring fra Ancestor komponentet, nemlig propertyen: MasterSource. Denne Property er af typen TRozhMySQLDataSource istedet for TDataSource.

Mit problem er at en Master/Detail relation fungerer ikke, når jeg bruger mine komponenter.

Er der nogen som vil hjælpe ?
Avatar billede rozh Nybegynder
22. maj 2004 - 17:08 #1
Og her er koden til mine to deriverede komponenter:


unit RozhsDBComponents;
{This unit hold the definitions of TRozhsMySQLDataSet and TRozhsDataSource}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, DB,
  MySQLDataSet, ActnList;

type
  TRozhsMySQLDataSet = class;
  TRozhsDataSource = class;

//------------------------------------------------------------------------------
  TDataSourceThread = class(TThread)
  private
    FRozhsDataSource: TRozhsDataSource;
  protected
    procedure Execute; override;
    property RozhDataSource: TRozhsDatasource
      read FRozhsDataSource write FRozhsDataSource;
  end;

//------------------------------------------------------------------------------
  TDataSetThread = class(TThread)
  private
    FRozhsMySQLDataSet: TRozhsMySQLDataSet;
  protected
    procedure Execute; override;
    property RozhsMySQLDataSet: TRozhsMySQLDataSet
      read FRozhsMySQLDataSet write FRozhsMySQLDataSet;
  end;

//------------------------------------------------------------------------------
  TDetailDataSetCollectionItem = class(TCollectionItem)
  private
    FDetailDataSet : TRozhsMySQLDataSet;
  protected
    function GetDisplayName : String; override;
  public
    procedure Assign(Source: TPersistent); override;
  published
    property DetailDataSet: TRozhsMySQLDataSet
      read FDetailDataSet write FDetailDataSet;
  end;

//------------------------------------------------------------------------------
  TDetailDataSetCollection = class(TCollection)
  private
    FOwner : TComponent;
  protected
    function GetOwner : TPersistent; override;
    function GetItem(Index: Integer): TDetailDataSetCollectionItem;
    procedure SetItem(Index: Integer; Value: TDetailDataSetCollectionItem); Reintroduce;
  public
    constructor Create(AOwner : TComponent);

    function Add : TDetailDataSetCollectionItem;
    function Insert(Index: Integer): TDetailDataSetCollectionItem;
    procedure delete(Index: Integer);
    property Items[Index: Integer]: TDetailDataSetCollectionItem
      read GetItem write SetItem; default;
  published
  end;

//------------------------------------------------------------------------------
  TRozhsDataSource = class(TDataSource)
  private
    FDetailDataSetCollection : TDetailDataSetCollection;
    FDataSourceThread: TDataSourceThread;
    procedure SetDetailDataSetCollection(const Value: TDetailDataSetCollection);
  protected
  public
    constructor Create(AOwner : TComponent); override;
    destructor Destroy; override;
    Procedure MyUpdate;
  published
    property DetailDataSetCollection : TDetailDataSetCollection
      read FDetailDataSetCollection write SetDetailDataSetCollection;
  end;

//------------------------------------------------------------------------------
  TRozhsMySQLDataSet = class(TMySQLDataSet)
  private
    FMasterSource:TRozhsDataSource;
    FDataSetThread: TDataSetThread;
  protected
  public
    Constructor Create(AOwner: TComponent); override;
    Destructor Destroy; override;
    Procedure MyUpdate;
    procedure SetMasterSource(const Value: TRozhsDataSource);
  published
    Property MasterSource: TRozhsDataSource
      read FMasterSource write SetMasterSource;
  end;

procedure Register;

implementation



//------------------------------------------------------------------------------
procedure Register;
begin
  RegisterComponents('Own Components', [TRozhsDataSource, TRozhsMySQLDataSet]);
end;

////////////////////////////////////////////////////////////////////////////////
{ TDataSourceThread }
////////////////////////////////////////////////////////////////////////////////

procedure TDataSourceThread.Execute;
begin
  while not terminated do
  begin
    synchronize(self.FRozhsDataSource.MyUpdate);
    sleep(100);
  end;
end;

////////////////////////////////////////////////////////////////////////////////
{ TDataSetThread }
////////////////////////////////////////////////////////////////////////////////

procedure TDataSetThread.Execute;
begin
  while not terminated do
  begin
    synchronize(self.FRozhsMySQLDataSet.MyUpdate);
    sleep(100);
  end;
end;

////////////////////////////////////////////////////////////////////////////////
{ TDetailDataSetCollectionItem }
////////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------------------
procedure TDetailDataSetCollectionItem.Assign(Source: TPersistent);
begin
  showmessage('assign');
  if Source is TDetailDataSetCollectionItem then
    DetailDataSet := TDetailDataSetCollectionItem(Source).DetailDataSet
  else
    inherited; //raises an exception
end;

//------------------------------------------------------------------------------
function TDetailDataSetCollectionItem.GetDisplayName: String;
begin
  if Self.DetailDataSet = nil then
    Result:= Format('Item %d',[Index])
  else
    Result:= Self.DetailDataSet.Name;
end;


////////////////////////////////////////////////////////////////////////////////
{ TDetailDataSetCollection }
////////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------------------
function TDetailDataSetCollection.Add: TDetailDataSetCollectionItem;
begin
  Result := TDetailDataSetCollectionItem(inherited Add);
end;

constructor TDetailDataSetCollection.Create(AOwner: TComponent);
begin
  inherited Create(TDetailDataSetCollectionItem);
  FOwner := AOwner;
end;

//------------------------------------------------------------------------------
function TDetailDataSetCollection.GetItem(Index: Integer):
                                                  TDetailDataSetCollectionItem;
begin
  Result := TDetailDataSetCollectionItem(inherited GetItem(Index));
end;

//------------------------------------------------------------------------------
function TDetailDataSetCollection.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

//------------------------------------------------------------------------------
function TDetailDataSetCollection.Insert(Index: Integer):
                                                  TDetailDataSetCollectionItem;
begin
  Result := TDetailDataSetCollectionItem(inherited Insert(Index));
end;


//------------------------------------------------------------------------------
procedure TDetailDataSetCollection.delete(Index: Integer);
begin
  inherited delete(index);
end;


//------------------------------------------------------------------------------
procedure TDetailDataSetCollection.SetItem(Index: Integer;
                                          Value: TDetailDataSetCollectionItem);
begin
  inherited SetItem(Index, Value);
end;


////////////////////////////////////////////////////////////////////////////////
{ TRozhsDataSource }
////////////////////////////////////////////////////////////////////////////////

Procedure TRozhsDataSource.MyUpdate;
var I:Integer;
begin
  for I:=0 to self.DetailDataSetCollection.Count-1 do
    if self.DetailDataSetCollection[I].DetailDataSet <> nil then
      if self.DetailDataSetCollection[I].DetailDataSet.MasterSource <> self then
        self.DetailDataSetCollection[I].DetailDataSet.MasterSource:= self;
end;


//------------------------------------------------------------------------------
constructor TRozhsDataSource.Create(AOwner: TComponent);
begin
  inherited;
  FDetailDataSetCollection := TDetailDataSetCollection.Create(Self);
  FDataSourceThread:=TDataSourceThread.Create(true);
  with FDataSourceThread do
  begin
    RozhDataSource:=self;
    Priority:= tpIdle;
    FreeOnTerminate:=false;
    Resume;
  end;
end;

//------------------------------------------------------------------------------
destructor TRozhsDataSource.Destroy;
  var I:Integer;
begin
  I:=0;
  while I < self.DetailDataSetCollection.Count do
    if self.DetailDataSetCollection[I].DetailDataSet <> nil then
      self.DetailDataSetCollection[I].DetailDataSet.MasterSource:=nil
    else
      inc(I);
  with FDataSourceThread do
  begin
    Terminate;
    WaitFor;
    Free;
  end;
  FDetailDataSetCollection.Free;
  inherited;
end;

//------------------------------------------------------------------------------
procedure TRozhsDataSource.SetDetailDataSetCollection
                                        (const Value: TDetailDataSetCollection);
begin
  FDetailDataSetCollection.Assign(Value);
end;

////////////////////////////////////////////////////////////////////////////////
{ TRozhsMySQLDataSet }
////////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------------------
constructor TRozhsMySQLDataSet.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDataSetThread:=TDataSetThread.Create(true);
  with FDataSetThread do
  begin
    RozhsMySQLDataSet:=self;
    Priority:= tpIdle;
    FreeOnTerminate:=false;
    Resume;
  end;
end;

//------------------------------------------------------------------------------
destructor TRozhsMySQLDataSet.Destroy;
begin
  self.MasterSource:=nil;
  with FDataSetThread do
  begin
    Terminate;
    WaitFor;
    Free;
  end;
  inherited Destroy;
end;

//------------------------------------------------------------------------------
procedure TRozhsMySQLDataSet.MyUpdate;
  var I,J: Integer;
      Indexes: array of Integer;
begin
  J:=0;
  setlength(Indexes,J);
  //checks if this DataSet is in its DataSource's list. If not, it sets its own
  //datasource to nil;
  if FMasterSource <> nil then
      for I:=0 to FMasterSource.DetailDataSetCollection.Count-1 do
        if FMasterSource.DetailDataSetCollection[I].DetailDataSet = self then
        begin
          inc(J);
          setlength(Indexes,J);
          Indexes[J-1]:=I;
        end;
  //if there is duplicates of this dataset in its mastersources list, then
  //delete the duplicates.
  for I:=J-1 downto 1 do
    FMasterSource.DetailDataSetCollection.delete(Indexes[I]);
  //if the dataset not found in its mastersource's list, set mastersource to nil
  if J=0 then FMasterSource := nil;
  setlength(Indexes,0);
end;

//------------------------------------------------------------------------------
procedure TRozhsMySQLDataSet.SetMasterSource(const Value: TRozhsDataSource);
  var I: Integer;
      found: boolean;
begin
  if FMasterSource <> value then
  begin
    I:=0;
    //delete self from current MasterSource, if not nil

    if FMasterSource <> nil then
      while I < FMasterSource.DetailDataSetCollection.Count do
        if FMasterSource.DetailDataSetCollection[I].DetailDataSet = self then
          FMasterSource.DetailDataSetCollection.delete(I)
        else
          inc(I);
    FMasterSource:=Value;
    //add self to new MasterSource, if not nil
    if Value <> nil then
    begin
      found:=false;
      //if RozhsMySQLdataSet is added from the design-time editor, then it
      //allready exists in the MasterSource's list.
      for I:=0 to FMasterSource.DetailDataSetCollection.Count-1 do
        if FMasterSource.DetailDataSetCollection[I].DetailDataSet = self then
          found:=true;
      if not found then
      begin
        FMasterSource.DetailDataSetCollection.Add;
        I:= FMasterSource.DetailDataSetCollection.Count-1;
        FMasterSource.DetailDataSetCollection[I].DetailDataSet:=self;
      end;
    end;
  end;
  inherited ;
end;


end.
Avatar billede rozh Nybegynder
01. juni 2004 - 23:24 #2
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester