Freitag, 21. November 2008

entwickler.com Magazine Konferenzen Akademie Entwickler-Forum Jobbörse Bücher
Software & Support Verlag

Datenmenge klonen

Frage: Ab Delphi 7 kann die Methode Clone direkt über die VCL aufgerufen werden. Nach dem Clonen müssen nun noch die Calc- und Lookupfields vom SourceDataSet in das CloneDataSet übertragen werden. Wie macht man das?

Antwort: Es wird eine Lösung für ein Problem gesucht, das gar nicht existiert! Die berechneten Spalten tauchen nur in der VCL-Welt (genau gesagt in TADODataSet) auf, das als Datenquelle darunterliegende Recordset-Objekt hat davon allerdings keine Ahnung. Daher sind nach dem Klonen der Datenmenge auch keine weiteren Aktionen notwendig, wie das folgende Beispiel demonstriert. Um das Beispiel nachzuvollziehen, sind die folgenden Schritte notwendig:

1. Beispieltabelle im MS SQL Server anlegen

2. TADOConnection und das originale TADODataSet konfigurieren, dabei die berechnete Spalte über den Feldeditor von Delphi zusätzlich anlegen

3. Ereignisbehandlungsmethode für OnCalcFields einrichten

4. Die fertig konfigurierte TADODataSet-Instanz über die Zwischenablage "klonen" und bei dem Klone die Verbindung zur Datenbank entfernen (d.h. die Eigenschaft Connection wird im Objektinspektor geleert). Der TADODataSet-Klon kann somit niemals auf die originale Datenbank-Tabelle zugreifen, sondern ist darauf angewiesen, vom Programm eine bereits gefüllte Datenmenge (Recordset-Objektinstanz) zu erhalten.

5. Der zweiten TADODataSet-Instanz eine eigene Ereignisbehandlungsmethode für OnCalcFields zuweisen

6. Zur Laufzeit der zweiten TADODataSet-Instanz die geklonte Recordset-Instanz unterschieben.

Schritt 1: Vorbereitung der Datenbank

USE tempdb
GO

CREATE TABLE CalcDemo ( RecID INTEGER NOT NULL IDENTITY PRIMARY KEY, Value1 INTEGER NOT NULL, Value2 INTEGER NOT NULL ) GO INSERT INTO CalcDemo (Value1,Value2) VALUES (2,3) INSERT INTO CalcDemo (Value1,Value2) VALUES (3,4) INSERT INTO CalcDemo (Value1,Value2) VALUES (4,5) INSERT INTO CalcDemo (Value1,Value2) VALUES (5,6) GO
Schritt 2: Programm

Beim Anklicken des Buttons wird die Datenmenge geklont und der zweiten TADODataSet-Instanz untergeschoben, die ebenfalls über die Zwischenablage von der ersten Instanz "geklont" wurde: Beide TDBGrid-Instanzen zeigen die korrekten Daten in der berechneten Spalte an, obwohl es diese Spalte im gefüllten Recordset überhaupt nicht gibt.
unit Unit1;

interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DB, ADODB, Grids, DBGrids, StdCtrls;
type TForm1 = class(TForm) DBGrid1: TDBGrid; ADOConnection1: TADOConnection; ADODataSet1: TADODataSet; DataSource1: TDataSource; ADODataSet1RecID: TAutoIncField; ADODataSet1Value1: TIntegerField; ADODataSet1Value2: TIntegerField; ADODataSet1CalcValue1Value2: TIntegerField; ButtonClone: TButton; ADODataSetCloneWithCalcField: TADODataSet; AutoIncField1: TAutoIncField; IntegerField1: TIntegerField; IntegerField2: TIntegerField; IntegerField3: TIntegerField; DBGrid2: TDBGrid; DataSourceClone: TDataSource; procedure ADODataSet1CalcFields(DataSet: TDataSet); procedure ButtonCloneClick(Sender: TObject); procedure ADODataSetCloneWithCalcFieldCalcFields(DataSet: TDataSet); private { Private-Deklarationen } public { Public-Deklarationen } end;
var Form1: TForm1;
implementation
{ *.dfm}
uses ADOInt;
procedure TForm1.ADODataSet1CalcFields(DataSet: TDataSet); begin ADODataSet1CalcValue1Value2.Value := ADODataSet1Value1.Value * ADODataSet1Value2.Value; end;
procedure TForm1.ButtonCloneClick(Sender: TObject); var aCloneRS : RecordSet; begin aCloneRS := ADODataSet1.Recordset.Clone(adLockUnspecified); ADODataSetCloneWithCalcField.Recordset := aCloneRS; ADODataSetCloneWithCalcField.Active := True; end;
procedure TForm1.ADODataSetCloneWithCalcFieldCalcFields(DataSet: TDataSet); begin IntegerField3.Value := IntegerField1.Value * IntegerField2.Value; end;
end.
Konfiguration des Formulars im Objektinspektor:
object Form1: TForm1
  Left = 192
  Top = 114
  Width = 870
  Height = 640
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object DBGrid1: TDBGrid
    Left = 8
    Top = 8
    Width = 377
    Height = 113
    DataSource = DataSource1
    TabOrder = 0
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'MS Sans Serif'
    TitleFont.Style = []
  end
  object ButtonClone: TButton
    Left = 96
    Top = 200
    Width = 75
    Height = 25
    Caption = 'Clone'
    TabOrder = 1
    OnClick = ButtonCloneClick
  end
  object DBGrid2: TDBGrid
    Left = 8
    Top = 240
    Width = 377
    Height = 120
    DataSource = DataSourceClone
    TabOrder = 2
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'MS Sans Serif'
    TitleFont.Style = []
  end
  object ADOConnection1: TADOConnection
    Connected = True
    ConnectionString = 
      'Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security In' +
      'fo=False;Initial Catalog=tempdb;Data Source=(local)'
    LoginPrompt = False
    Provider = 'SQLOLEDB.1'
    Left = 120
    Top = 64
  end
  object ADODataSet1: TADODataSet
    Active = True
    Connection = ADOConnection1
    CursorType = ctStatic
    OnCalcFields = ADODataSet1CalcFields
    CommandText = 'select RecID, Value1, Value2 from CalcDemo'
    Parameters = <>
    Left = 160
    Top = 64
    object ADODataSet1RecID: TAutoIncField
      FieldName = 'RecID'
      ReadOnly = True
    end
    object ADODataSet1Value1: TIntegerField
      FieldName = 'Value1'
    end
    object ADODataSet1Value2: TIntegerField
      FieldName = 'Value2'
    end
    object ADODataSet1CalcValue1Value2: TIntegerField
      FieldKind = fkCalculated
      FieldName = 'CalcValue1Value2'
      Calculated = True
    end
  end
  object DataSource1: TDataSource
    DataSet = ADODataSet1
    Left = 192
    Top = 64
  end
  object ADODataSetCloneWithCalcField: TADODataSet
    CursorType = ctStatic
    OnCalcFields = ADODataSetCloneWithCalcFieldCalcFields
    CommandText = 'select RecID, Value1, Value2 from CalcDemo'
    Parameters = <>
    Left = 48
    Top = 296
    object AutoIncField1: TAutoIncField
      FieldName = 'RecID'
      ReadOnly = True
    end
    object IntegerField1: TIntegerField
      FieldName = 'Value1'
    end
    object IntegerField2: TIntegerField
      FieldName = 'Value2'
    end
    object IntegerField3: TIntegerField
      FieldKind = fkCalculated
      FieldName = 'CalcValue1Value2'
      Calculated = True
    end
  end
  object DataSourceClone: TDataSource
    DataSet = ADODataSetCloneWithCalcField
    Left = 88
    Top = 296
  end
end






Software & Support Verlag GmbH