Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   ClientDataSet; Datenmenge wird ungewollt zur aktuellen hinzugefügt, warum? (https://www.delphipraxis.net/180891-clientdataset%3B-datenmenge-wird-ungewollt-zur-aktuellen-hinzugefuegt-warum.html)

FragenderHerbert 28. Jun 2014 10:59

Datenbank: Dbase • Version: 4 • Zugriff über: TClientDataSet

ClientDataSet; Datenmenge wird ungewollt zur aktuellen hinzugefügt, warum?
 
Hallo,

ich stehe vor demProblem, das ich eine CD-, Video und PC-Datenträgerverwaltung bauen will, die folgendes leistet:

ich gebe in einer Masterdatei mit den Feldern

MEDIAID, zB. CD0001 oder DVD0002

MEDIAKIND und evtl noch zB. music, video oder software

FILENAME zb. MusikCDs.dbf oder Videos.dbf oder SoftwBackups.dbf

eine Datenmenge vor, die mit den Detaildatenbanken wie MusikCds.dbf, ... verknüpft ist und mir bei Auswahl einer MEDIAID den Inhalt des jeweiligen Datentägers anzeigt. Später will ich mit dem Programm auch gezielt nach einemTitel suchen können und die Bezeichnung des Speichermediums als Ergebnis der Abfrage haben.

Die Motivation hierzu ergibt sich aus dem Umstand das ich oft schon SOftwarebibliotheken, heruntergeladene Quelltexte, ... nach langer Zeit mal wieder benutzen will und dann nicht mehr weiß, auf welchem Medium und in welchem Ordner auf diesem Medium ich denn nun das Zeug gespeichert habe.

Mein derzeitiger Ansatz:

Delphi-Quellcode:
unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, ADODB, DB, ExtCtrls, DBCtrls, Grids, DBGrids, dbf, Provider,
  DBClient;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Login1: TMenuItem;
    N1: TMenuItem;
    Exit1: TMenuItem;
    DBGrid1: TDBGrid;           //Masterdaten anzeigen
    DBNavigator1: TDBNavigator;
    Dbf1: TDbf;                 //Zugriff auf Masterdaten
    DataSource1: TDataSource;   //Datenquelle Masterdaten
    DataSource2: TDataSource;   //Datenquelle Detaildaten, zB. MusikCds
    Dbf2: TDbf;                 //Zugriff auf Detaildaten
    Dbf3: TDbf;                 //Vorläufiger Zugriff auf Detaildaten einer weiteren Tabelle (***)
    DataSource3: TDataSource;   //Datenquelle dieser Detaildaten
    DBNavigator2: TDBNavigator;
    DBGrid2: TDBGrid;           //Detaildaten anzeigen
    ClientDataSet1: TClientDataSet;      //Weil Master/Detail mit TDBF nicht funktioniert
    DataSetProvider1: TDataSetProvider;  //mit Dbf2, meiner ersten Detailtabelle verbunden
    DataSource4: TDataSource;            //Die Datnquelle hierzu zum Anzeigen in DBGrid3
    DBNavigator3: TDBNavigator;
    DBGrid3: TDBGrid;                    //Hier ist es
    procedure Exit1Click(Sender: TObject);
    procedure DataSource1DataChange(Sender: TObject; Field: TField);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
var RefField, ResField: WideString;
begin
  RefField := TDataSource(Sender).DataSet.Fields.FieldByName('MEDIAID').AsString;
  //dbf2.Locate(RefField, Field.CurValue, [loCaseInsensitive]); //Hier wird Exception geworfen
end;

procedure TForm1.Exit1Click(Sender: TObject);
begin
  Application.Terminate();
end;

end.
Mein Problem ist jetzt, das, wenn ich zB. CD0001 anwähle, dann ist die Anzeige korrekt, wenn ich aber dann CD0002 anwähle, ist die Anzeige zunächst auch korrekt, wenn ich dann aber zurück auf CD0001 gehe, wird mir die zugehörige Detaildatenmenge 2 Mal angezeigt. Wenn ich dann auf den dritten Masterdatensatz gehe und danach zurück, erscheint die datenmenge 3 Mal. Ich will sie natürlich in jedem Fall nur einmal sehen.

EDataBaseError: Operation bei geschlossener Datenmenge nicht ausführbar.

Wenn ich jedoch alles im Objektinsprktor einstelle, auch DataSet.Active = true, dann ist doch die Datenmenge geöffnet?

Warum kann ich das dann nicht voraussetzen, wenn ich jetzt Quelltext schreibe, um in meinm Fall auf Änderungen in einer Datenmenge, hier Satznummer in den Masterdaten, zu reagieren?

Was muss ich dazu noch einstellen?

himitsu 28. Jun 2014 11:24

AW: ClientDataSet; Datenmenge wird ungewollt zur aktuellen hinzugefügt, warum?
 
Du solltest erstmal bedenken, daß der Parameter "Field" nicht immer ein Feld enthalten muß und auch mal nil sein kann.
  • erstmal sagt dir die Exception-Message, welche du uns vorenthälst, ganz bestimmt was von "Zugriffsverletzung bei Adresse $000000xx" und schon weiß man, daß da irgendwo ein NIL im Spiel ist
  • und wenn man den Debugger verwenden würde, dann würde man auch sehen, daß dieses Property bestimmt NIL sein wird

Aber warum verwendest du nicht die Master-Detail-Funktionen des ClientDataSets, und lässt das automatisch synchronisieren?
  • IndexFieldNames
  • MasterFields
  • MasterSource

Oder man verwendet zum Ausrichten DataSet.OnAfterScroll.


Sicher, daß du Locate richtig verwendest, oder täuscht das nur und du hast eine etwas "eigenartige" Tabellenstruktur? (welche natprlich auch geheim ist)
  • ID als Feldname



PS: Statt
Delphi-Quellcode:
Application.Terminate;
kommt man mit
Delphi-Quellcode:
{Self}.Close;
oder
Delphi-Quellcode:
Application.MainForm.Close;
besser, denn damit verbaut man sich die Nutzung von TForm.OnCloseQuery nicht.
Das (erfolgreiche) Schließen der Hauptform beendet die Application, aber so kann man prüfen, ob wirklich geschlossen werden darf. z.B. wenn noch nicht gepseichert wurde.

FragenderHerbert 28. Jun 2014 12:56

AW: ClientDataSet; Datenmenge wird ungewollt zur aktuellen hinzugefügt, warum?
 
Zitat:

Zitat von himitsu (Beitrag 1263686)
Du solltest erstmal bedenken, daß der Parameter "Field" nicht immer ein Feld enthalten muß und auch mal nil sein kann.

Ok, das könnte die Ursache meiner Exception sein. Ich habe stillschweigend vorausgesetzt, das der Event-Handler zwingend einen Feldinhalt übergibt und deshalb dort nicht gesucht.

Zitat:

Zitat von himitsu (Beitrag 1263686)
  • erstmal sagt dir die Exception-Message, welche du uns vorenthälst, ganz bestimmt was von "Zugriffsverletzung bei Adresse $000000xx" und schon weiß man, daß da irgendwo ein NIL im Spiel ist
  • und wenn man den Debugger verwenden würde, dann würde man auch sehen, daß dieses Property bestimmt NIL sein wird

Und genau da ist das Problem! Wo ist irgendwo, wo ja der Nil Zeiger sein müsste?
Noch mal: Ich habe gar nicht mit irgendeinem NIL Zeiger gerechnet, da ich eine EDataBaseError Exception erhalten habe. Kann ja sein, das mein Konzept im Grundsatz schon falsch ist. Aber wie kann ich es dann besser machen. Eine Client-Server Architektur will ich absichtlich nicht, da ich mich noch nicht mal mit den elementarsten Grundlagen auskenne und auch die Delphi-Treff Tut-s hier nicht viel her geben.

Eine andere für mich hoch interessante Frage ist für mich im Gesamtzusammenhang: Wo finde ich ein einsteigerfreundliches Lehrbuch zu SQL Syntax. Möglichst MSSQL, da ich mich an CS Arcitekturen noch nicht heran traue und meine Medienverwaltung ausschließlich auf einem meiner lokalen Computer laufen soll, möglichst portabel auf einem USB Stick. Die Medienverwaltung soll deshalb keine vorinstallierten Datenbankserver voraussetzen. Leider kriege ich bei ADO den Verbindungsstring nicht "gebacken", ich erhalte dann Fehlermeldung, das die Tabelle nicht vorhanden ist. Ich habe da als Treiber den:

- OLE DB Simple Provider sowie den
- OLE DB Provider für Microsoft Directory Services

getestet.

Bei beiden kommt die Fehlermeldung "Tabelle nicht vorhanden"

Bei letzterem muss ich u.a. Datenquelle und Speicherort separat angeben.

Datenquelle -> meine Datenbankdatei
Speicherort -> mein Datenbankverzeichnis

Die Adresse 127.0.0.1 wird als Speicherort nicht akzeptiert. Daher habe ich "http://localhost" gar nicht erst probiert.

Ich will eine lokale Datenbank haben, da die für meine Zwecke komplett ausreicht und ich mir deshalb die Einarbeitung in CS Architekturen noch sparen möchte. Weil ich aber eine portable Anwendung will, scheidet BDE sofort aus. Bei Interbase bräuchte ich eine portable Version des Servers. Das hätte aber dann wohl zur Folge, das ich um die Erlernung der CS Architektur nicht herum käme.

Debuggen kann ich erst effektiv, wenn ich weiß, wo ich den Fehler suchen muss. Wenn ich den Fehlerort nicht eingrenzen kann, bin ich mit dem Test anderer DB Kompos genau so schnell oder gar schneller am Ziel.

Zitat:

Aber warum verwendest du nicht die Master-Detail-Funktionen des ClientDataSets, und lässt das automatisch synchronisieren?
  • IndexFieldNames
  • MasterFields
  • MasterSource

Doch, das habe ich schon erledigt. Alles im Objektinspector. Per Quelltext mache ich das zur Übung später, wenn ich das per OI geschafft habe.

Zitat:

Sicher, daß du Locate richtig verwendest, oder täuscht das nur und du hast eine etwas "eigenartige" Tabellenstruktur? (welche natprlich auch geheim ist)
  • ID als Feldname

Nein, bin ich nicht. Habe soeben das hier dazu gefunden:
http://www.delphipages.com/forum/showthread.php?t=41929

Da gibt es u.a. diesen Beitrag im Forum:

Zitat:

Change the comma to a semicolon in the Field string.
Example:

Locate('FIELD1;FIELD2;FIELD3',VarArrayOf([Value1,Value2,Value3]),[]);

Happy New Year
Christian
Allerdings brauche ich das variabel, das heißt -> Value1 muss der aktuelle Wert aus der Mastertabelle sein (CD0001,CD0002,DVD0001,USB-Stick0003,...)

Wenn aber der Parameter Field im Eventhandler der DataSource auch NIL sein kann?
Habe inzwischen den Quellcode schon in einen try except Block eingeschlossen. Aber mein EDatabaseError wird vor dem eingentlichen Start schon geworfen. Ich will aber, das in diesem Fall eben nix passiert. Wie aber stelle ich das an. Sorry, aber ich bin in Sachen Datenbank ein totales Greenhorn.

Bei dieser Gelegenheit frag ich gleich mal, wo gibt es denn wirklich einsteigerfreundliche Literatur zu Datenbanken? Ich habe außerdem Xampp auf meinem System installiert. Der beherrscht auch MySQL. Aber wo gibt es einsteigerfreundliche Tuts dazu?

Dejan Vu 29. Jun 2014 10:50

AW: ClientDataSet; Datenmenge wird ungewollt zur aktuellen hinzugefügt, warum?
 
Im OnDataChange bezeichnet der Field-Parameter das Feld, welches verändert wurde. Wenn Field=nil, dann findet ein Wechsel des aktuellen Datensatzes statt.

Bezüglich der Master-Detail-Beziehung setzt Du in der Detail-Datenmenge die 'MasterSource'-Eigenschaft auf das Dateset des Master-Datasets. Anschließend setzt Du die Master-Fields Eigenschaft entsprechend.

Das sollte das Problem lösen.

Es kann allerdings schneller sein, wenn Du einmalig alle Detaildaten lädst und dann die Detaildaten über die Filter-Eigenschaft beim Record-Wechsel (OnDataChange mit Field=nil ;-) ) neu setzt.

blawen 29. Jun 2014 12:16

AW: ClientDataSet; Datenmenge wird ungewollt zur aktuellen hinzugefügt, warum?
 
Zitat:

Zitat von FragenderHerbert (Beitrag 1263687)
Bei dieser Gelegenheit frag ich gleich mal, wo gibt es denn wirklich einsteigerfreundliche Literatur zu Datenbanken? Ich habe außerdem Xampp auf meinem System installiert. Der beherrscht auch MySQL. Aber wo gibt es einsteigerfreundliche Tuts dazu?

Da Du für Dich selbst die Tutorials von Delphi Treff nicht viel hergeben (Zitat), wird es für meine Glaskugel schwierig, abzuschätzen, welches der abertausenden Tuts Deinen Ansprüchen gerecht wird.
Vielleicht passt's ja:
Tut von Luckie

Neben den Text-Tuts findest Du bei Youtube auch massig Video-Tutorials.

Wenns ein Buch sein soll:
MySQL Handbuch

Sir Rufo 29. Jun 2014 12:28

AW: ClientDataSet; Datenmenge wird ungewollt zur aktuellen hinzugefügt, warum?
 
Zitat:

Möglichst MSSQL, da ich mich an CS Arcitekturen noch nicht heran traue und meine Medienverwaltung ausschließlich auf einem meiner lokalen Computer laufen soll, möglichst portabel auf einem USB Stick. Die Medienverwaltung soll deshalb keine vorinstallierten Datenbankserver voraussetzen.
Bei portabel und nicht installiertem Datenbankserver würde mir MSSQL eigentlich nicht in den Sinn kommen, aber gut
Zitat:

- OLE DB Simple Provider sowie den
- OLE DB Provider für Microsoft Directory Services
Ja, damit würde ich auch keine Verbindung zu - ja zu was denn jetzt - hinbekommen.
Du musst schon den DB Provider bemühen, der auch mit dem Datenbanksystem sprechen kann (die beiden sind es nicht).

Und wenn du schon eine Master-Detail-Beziehung per OI definiert hast, warum willst du da per Code nochmals reinpfuschen? sehr seltsam ...

FragenderHerbert 29. Jun 2014 15:01

AW: ClientDataSet; Datenmenge wird ungewollt zur aktuellen hinzugefügt, warum?
 
Zitat:

Zitat von blawen (Beitrag 1263716)
Zitat:

Zitat von FragenderHerbert (Beitrag 1263687)
Bei dieser Gelegenheit frag ich gleich mal, wo gibt es denn wirklich einsteigerfreundliche Literatur zu Datenbanken? Ich habe außerdem Xampp auf meinem System installiert. Der beherrscht auch MySQL. Aber wo gibt es einsteigerfreundliche Tuts dazu?

Da Du für Dich selbst die Tutorials von Delphi Treff nicht viel hergeben (Zitat), wird es für meine Glaskugel schwierig, abzuschätzen, welches der abertausenden Tuts Deinen Ansprüchen gerecht wird.
Vielleicht passt's ja:
Tut von Luckie

Neben den Text-Tuts findest Du bei Youtube auch massig Video-Tutorials.

Wenns ein Buch sein soll:
MySQL Handbuch

Danke! Werd mir beide anschauen. Die Leseprobe des MySQL Handbuches sieht gut aus und von Lukie hab ich mir schon die WIN-API Tuts gesaugt. Dort ist die Praxis unter Benutzung von Delphi gut erklärt. Im hier verlinkten Tut von Luclie hab ich jetzt nur kurz gelesen, schaut aber auch gut aus. Werde mich also damit erst mal beschäftigen. Das MySQL Handbuch ist dann zusätzlich.

Perlsau 2. Jul 2014 13:22

AW: ClientDataSet; Datenmenge wird ungewollt zur aktuellen hinzugefügt, warum?
 
Zitat:

Zitat von FragenderHerbert (Beitrag 1263685)
Die Motivation hierzu ergibt sich aus dem Umstand das ich oft schon SOftwarebibliotheken, heruntergeladene Quelltexte, ... nach langer Zeit mal wieder benutzen will und dann nicht mehr weiß, auf welchem Medium und in welchem Ordner auf diesem Medium ich denn nun das Zeug gespeichert habe.

Abgesehen von deinem Datenbank-Problem: Ich hatte noch nie Schwierigkeiten, irgend eine heruntergeladene Datei wieder zu finden, denn ich verwende ein ganz bestimmtes System, auch für meine Delphi-Projekte:
Mein Archiv-Ordner auf meinem Backup-Laufwerk (3 TB) sieht ungefähr so aus (unvollständig):

Code:
Archiv
 Anwendungen
  Audio
  DBMS
  Grafik
  ...
  Utils
 Coding
  Apps
   Delphi
    Ide-Erweiterungen
    Komponenten
    Tools
   Java
   Lazarus
   ...
  Codes
   Projekte
    Auftrag
    ...
    Test
  Datenbanken
   Access
   Firebird
   MsSQL
   MySQL
  Utils
 Texte
 Grafik
Wenn man heruntergeladene Dateien immer sauber in die entsprechende Kategorie einordnet, findet man das auch wieder, ganz ohne Datenbank. Zu guter Letzt gibt's ja auch noch die Windows-Suchfunktion und den Windows-Indexdienst ...


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:57 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz