Einzelnen Beitrag anzeigen

Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.388 Beiträge
 
Delphi 12 Athens
 
#14

AW: Absturz des SQL-Editors in der IDE (D7/ADS10.1)

  Alt 19. Mär 2017, 07:42
Moin...
Zitat:
Zu Deinem ersten Beispiel: die FillQuery-Methode hat Query als Var. und Param. Da ist mir die Funktionsweise nicht ganz klar. Soll der Parameter mit einem Query versorgt werden (falls er bei Übergabe nil ist)? Dann müsste er als var übergeben werden. Wenn er gefüllt ist, müsste man erst einen Close machen, falls er noch aktiv ist:
Der Varianten gibt es verschiedene... Zum Einen eine function die Query als Rückgabewert hat oder die Variante mit der Übergabe der Query als Parameter. Wenn man sich die Variante der function entschieden hat, sollte der Name ausdrücken das innerhalb eine neue Instanz erzeugt wird. (bsp. CreateMeinDataSet). Bei der Parametervariante erfolgt Erzeugung der Instanz in der gleichen Ebene wie die Freigabe.
Delphi-Quellcode:
function TDatabase.CreateMeinDataSet(Parameter: TMeineParameter): TDataSet;
  Query: TUniQuery;
begin
  Query := CreateQuery; // hier wir die Instanz erzeugt
  Query.SQL.Text := 'SELECT F_BLUBB FROM T_BLA';
  Query.Open;
end;
.
procedure TDatabase.FillQuery(Query: TDataSet);
  Query: TUniQuery;
begin
  Query.SQL.Text := 'SELECT F_BLUBB FROM T_BLA';
  Query.Open;
end;
Zitat:
Wenn ich komplett auf Komponenten verzichte, dann müsste ich ja "einfache" TLabel, TEdit, ... einfügen und mit DataToForm- bzw. FormToData-Methoden die Felder befüllen (KundenNrLabel.Caption := Query.FieldByName('KUNDENNR').Text). Das wäre jetzt (solange man auf TDataSet als Basis setzt) datenbankunabhängig.
...JA. Ich versuche dich von den datensensitiven Komponenten abzuhalten. Auch wenn es mehr Arbeit erscheint, diese Arbeit wirst du schätzen wissen wenn du die Komponenten gegen schönere austauschst.
Zitat:
Würde man das dann in eine Methode "KundeToForm(const Vorname, Nachname, Strasse, Ort : TControl" packen, der ich diverse Controls übergeben kann (TLabel, TEdit, ...) und die Werte dann zugewiesen werden, wenn ich ein Control übergeben habe (if Vorname is TLabel then ... else if Vorname is TEdit then ...)?
...NÖ umkekehrt. Spendiere deiner Form eine Property mit den Daten (TDataset). Wenn du die Form erzeugst/anzeigst gibst du das Dataset mit, welches du zuvor geladen hast und die Daten enthällt. Wenn du die Daten in Objektlisten hast, übergibst der Form das Objekt aus der Liste. Innerhalb der Form kannst du enweder auf das Objekt oder mit DataSet.FieldByName auf die Daten zugreifen und die Controls füllen. Das Speichern funktioniert in umgegehrter Reihenfolge...
Delphi-Quellcode:
TfoBlubb = class(TForm)
  edtName: TEdit;
  edtCaption: TEdit;
strict private
  FBlubbDaSet: TDataSet;
public
  property BlubbDataSet: TBlubbDataSet read FBlubbDaSet write FBlubbDaSet;
end;
...
edtName.Text := FBubbDataSet.FieldByName('NAME').AsString;
...
// Alternativ mit Objekten wenn man eines übergibt
edtName.Text := FBlubb.Name;
...mit Objekten brauchst du die FeldNamen nicht kennen.
Zitat:
TGrid: Würdest Du dann ein CustomGrid machen und die Verbindung zu Query selbst bauen? Oder ein datensensitives TDBGrid nehmen, das dann alle gelieferten Felder anzeigt, wenn ich es zur Laufzeit mit einem TDataSet verbinde? (Dritt-Komponenten mal außen vor)
...sicherlich geht das mit dem DBGrid und DataSource. Damit bindest du du dich an dieses eine Control. Als Beispiel nehme ich immer: Wenn es dir nicht mehr gefällt kannst du es nicht (sinngemäß) einfach austauschen. (Sichwort: Trennung der Oberfläche von den Daten)
Zitat:
An den Aufruf "GetSQLByName" hatte ich auch schon gedacht. Aber dann muss der Aufrufer ja doch wieder wissen, wie die Parameter und die gelesenen Felder heißen von dem, was GetSQLByName liefert.
Das stammt aus meiner Variante mit der Ressource. GetSQLByName gibt anhand des Namens in der Ressource das komplette Statement zurück.
WERBUNG : http://www.delphipraxis.net/190316-d...e-creator.html siehe Tutorial und Anleitung.
Zitat:
Da finde ich es praktischer, hier gleich den SQL-String stehen zu haben, dann sehe ich beim auscodieren der FieldByName-Aufrufe gleich wie meine Felder heißen. Verstehst Du, was ich meine?
...ja. Da ich nicht mehr mit DataSet in der Anwendung, sondern mit Objekten arbeite, habe ich nur ein Mal nach dem Auslesen die FieldByName Aufrufe.
Zitat:
Aber in der Save-Methode von TDatabase wird dann doch "Wissen" der Tabelle benötigt, da Du ja die Felder UID und GRO explizit ansprichst. Oder sollten die grundsätzlich immer bei allen Tabellen da sein? Oder Wird TDatabase für jede Tabelle abgeleitet und Load/Save entsprechend auscodiert
...ja, auscodiert. Die Klasse enthällt die Methoden für den Zugriff auf die benötigten Tabellen.
Beispiel: stark gekürzt!
Delphi-Quellcode:
IdVA_Database = interface(IdDatabase)

TDatabaseIB = class(TInterfacedObject, IdDatabase) //in der Anwendung existiert nur das Interface für alle gleich.
  strict private
    FConnection: TUniConnection;
    FConnected: Boolean;
    function GetConnected: Boolean;
  public
    constructor Create;
    destructor Destroy; override;

    property Connected: Boolean read GetConnected;
    function Connect: Boolean;
    procedure Disconnect;
    procedure StartTransaction;
    procedure Commit;
    procedure Rollback;

    procedure CreateDatabase;
    function CreateQuery: TUniQuery;
    function CreateStoredProc: TUniStoredProc;
    function GetSQLByName(SQLName: string): string;
    procedure ExecuteScript(SQL: TStrings);
    // Beispiele
    function Save(UserRole: TdUserRole): Integer; overload;
    function Save(User: TdUser): Integer; overload;
    
    procedure SaveList(aList: TAlarmStateList); overload;
    procedure SaveList(aList: TDeviceList); overload;

    procedure Get(User: TdUser; UserName: string); overload;
    procedure Get(Device: TDevice; ID: Integer); overload;

    procedure FillList(aList: TMasterDeviceList); overload;
    procedure FillList(List: TdUserList; UserID: Integer = -1); overload;
  end;
Zitat:
Noch ein anderer Gedanke zum "individuellen QueryBuilder": wenn ich z.B. die Daten eines Kunden auf dem Dialog im Kunden-Stamm, auf dem Lieferschein und auf der Rechnung anzeigen will, mache ich dann unterschiedliche Queries zw. Query-Methoden, da ich beim KundenStam mehr Daten lesen will als für den Lieferschein/die Rechnung? Oder versuche ich die anzahl der verschiedenen Queries klein zu halten und baue nur ein Query, der immer alle Felder liest und ich verwende dann nur die, die ich im Kontakt gerade brauche
...Querys thematisch trennen! Wenn du z.B. die Lieferantendaten an verschiedenen stellen benötigst, würde es Sinn machen die nicht doppelt anzulegen...

Du bist an dem Punkt wo du entscheiden mußt welche Technik du benutzen willst. Letztendlich muß es zu dir passen... Lieber über die Entscheidung lange nachdenken und mit Beispielen ausprobieren. Wenn du einmal die Anwendung angefangen hast, ist es eher nicht möglich die Methode der Datenbeschaffung zu wechseln.

Aus der Erfahrung heraus:
Ich bin für Objekte in Listen. Da kann man sich die Daten bliebig zusammensetzen...auch aus verschieden Tabellen. Das Laden/Speichern übernimmt das Database "Modul". Dem Objekt ist die Quelle der Daten egal. Der Anwendung ist es wurscht wie Daten in das Objekt gekommen sind...Datenbank, XML, Omas Küchenschrank. Wenn du in der Anwendung mit der DataSet Ebene arbeitest hast du quasi mit FieldByName eine Bindung zu einer Datenbank. (auch wenn es Möglichkeiten gibt ein DataSet aus anderen Quellen zu erstellen)
DBGrid alles schön und gut. Du wirst aber an den Punkt kommen das die Query im Grid angezeigt werden kann, aber weil du JOINS benutzt hast, das DataSet nicht gespeichert werden kann.
Da fängst du dann an umzubauen weil deine Anforderung gestiegen ist. Dadurch entstehen die berühmten Workarounds...


Geändert von haentschman (19. Mär 2017 um 17:38 Uhr)
  Mit Zitat antworten Zitat