|
Antwort |
haentschman
Online
Registriert seit: 24. Okt 2006
Hallo...
Das ist mein erstes Tutorial. Bitte seid gnädig... Es soll als Anregung dienen wie man auch ohne datensensitive Controls auskommt. Ich möchte Euch zeigen, wie man programmintern mit Objekten arbeitet und diese Objekte in einer normalisierten Datenbank speichert. Im Prinzip ist es ein Mini-ORM ohne externes Framework. Der Kreativität sind keine Grenzen gesetzt. Ich habe versucht das einfach zu halten. Mancher Code könnte mit unterschiedlichen Methoden realisiert werden. (JOIN statt separater procedure) Welche Variante man nimmt, ist jedem selbst überlassen. Hinweise: * Weil die Units zu lang sind... siehe Projekt. * Weil nicht alle das compilieren können ist die EXE zum Ausprobieren dabei... siehe Projekt * Die Zwischenvariablen (wie var Customer: TCustomer; in Main) sind nicht immer notwendig aber es macht es für den Anfang imho übersichtlicher. Anhänge: * Projekt mit Datenbank ausführbar. * kompletter Quelltext D10.1 Voraussetzungen: Delphi XE und höher wegen Generics im Beispiel Aufbau 3 Schicht Anwendung: (Unit: FormMain) -> (Unit: Logic) -> (Unit: Database) -> (Database: z.B.Firebird) <- (Event) <- (Event) Database (beliebiebiges DBMS)
Code:
Unit: Database
CREATE TABLE T_CUSTOMER (
ID INTEGER NOT NULL, F_NAME VARCHAR(50), F_FIRST_NAME VARCHAR(50), F_ADDRESS_ID INTEGER ); CREATE TABLE T_ADDRESS ( ID INTEGER NOT NULL, F_POSTCODE VARCHAR(30), F_TOWN VARCHAR(50), F_STREET VARCHAR(50), F_HOUSE_NUMBER VARCHAR(10) ); In dieser Unit ist die Schnittstelle zur Datenbank definiert. In diesem Falle als Interface. Die Logik kennt nur das Interface welches in der Logik instanziert wird. (siehe Unit: Logik) Die Querys werden nicht mehr auf die Form "geklatscht" und dort die SQL eingetragen. Das Interface kennt alleinig die SQL Statements. Das macht es einfacher mehrere Datenbanken anzubinden. Für jede Datenbank gibt es dann ein eigenes Interface wegen der Unterschiede der möglichen Datenbanken. Als Datenbankkomponenten kommen hier die UniDAC mit der Schnittstelle zu Firebird zum Einsatz. Andere Komponenten sind natürlich auch möglich. Diese eine Unit kennt allein die Datenbank. Die Kommunikation mit der Logik, welche die Unit nicht kennt, kann sowohl über Events oder als Rückgabe der Funktion aus der Logik erfolgen. Interface:
Delphi-Quellcode:
Database gekürzt:
unit Database.Interfaces;
interface uses Logic.DataClasses, Database.Events; type IDatabaseCommon = interface(IInterface) // ggf. in seperate Unit bei mehreren DBMS ['{E41ADEE8-56F9-4223-8238-61B6C033DFF1}'] function GetAfterConnect: TOnAfterConnectEvent; procedure SetAfterConnect(const Value: TOnAfterConnectEvent); function GetDatabaseError: TOnDatabaseErrorEvent; procedure SetDatabaseError(const Value: TOnDatabaseErrorEvent); function GetAfterDisconnect: TOnAfterDisconnectEvent; procedure SetAfterDisconnect(const Value: TOnAfterDisconnectEvent); property OnAfterConnect: TOnAfterConnectEvent read GetAfterConnect write SetAfterConnect; property OnAfterDisconnect: TOnAfterDisconnectEvent read GetAfterDisconnect write SetAfterDisconnect; property OnDatabaseError: TOnDatabaseErrorEvent read GetDatabaseError write SetDatabaseError; function Connect: Boolean; procedure Disconnect; procedure StartTransaction; procedure Commit; procedure Rollback; function GetSQLByName(SQLName: string): string; // ggf. bei Laden des SQL Statements aus Ressource end; IDatabase = interface(IDatabaseCommon) ['{C1BC6FE3-9586-4D92-8221-A3DD030E80B5}'] // Entweder overload oder als einzelne Prozeduren, der Creativität sind keine Grenzen gesetzt. procedure FillList(List: TCustomerList); overload; function Save(Customer: TCustomer): Integer; overload; function Save(Address: TAddress): Integer; overload; procedure Get(Customer: TCustomer; ID: Integer); overload; procedure Get(Address: TAddress; ID: Integer); overload; // kann auch separat genutzt werden...oder auch nicht end; implementation end.
Delphi-Quellcode:
Unit: Logic
unit Database.Firebird;
interface uses System.Classes, System.SysUtils, System.Variants, System.Generics.Collections, System.Generics.Defaults, System.DateUtils, Uni, DBAccess, InterBaseUniProvider, Database.Interfaces, Database.Events, Logic.DataClasses; type TDatabaseFirebird = class(TInterfacedObject, IDatabase) strict private // Properties Connection FConnection: TUniConnection; FOnAfterConnect: TOnAfterConnectEvent; FOnAfterDisconnect: TOnAfterDisconnectEvent; FOnDatabaseError: TOnDatabaseErrorEvent; // Getter / Setter function GetAfterConnect: TOnAfterConnectEvent; procedure SetAfterConnect(const Value: TOnAfterConnectEvent); function GetDatabaseError: TOnDatabaseErrorEvent; procedure SetDatabaseError(const Value: TOnDatabaseErrorEvent); function GetAfterDisconnect: TOnAfterDisconnectEvent; procedure SetAfterDisconnect(const Value: TOnAfterDisconnectEvent); // Eventhandler procedure DoAfterConnect(Sender: TObject); procedure DoAfterDisconnect(Sender: TObject); procedure DoError(Sender: TObject; E: EDAError; var Fail: Boolean); // Funktionen function CreateQuery: TUniQuery; public constructor Create; destructor Destroy; override; // Events property OnAfterConnect: TOnAfterConnectEvent read GetAfterConnect write SetAfterConnect; property OnAfterDisconnect: TOnAfterDisconnectEvent read GetAfterDisconnect write SetAfterDisconnect; property OnDatabaseError: TOnDatabaseErrorEvent read GetDatabaseError write SetDatabaseError; // Funktionen aus Interface function Connect: Boolean; procedure Disconnect; procedure StartTransaction; procedure Commit; procedure Rollback; function GetSQLByName(SQLName: string): string; // ggf. bei Laden des SQL Statements aus Ressource procedure FillList(List: TCustomerList); overload; function Save(Customer: TCustomer): Integer; overload; function Save(Address: TAddress): Integer; overload; procedure Get(Customer: TCustomer; ID: Integer); overload; procedure Get(Address: TAddress; ID: Integer); overload; // kann auch separat genutzt werden...oder auch nicht end; ... In dieser Unit ist die Logik definiert. Die Logik nimmt die Befehle der Form entgegen und führt diese aus. Desweiteren hällt die Logik die Daten der Anwendung. In diesem Falle die CustomerList. Die Kommunikation mit der Form, welche die Unit nicht kennt, kann sowohl über Events oder als Rückgabe der Function aus der Logik erfolgen. Klassendefinition gekürzt:
Delphi-Quellcode:
Logic gekürzt:
unit Logic.DataClasses;
interface uses System.Generics.Collections, System.Generics.Defaults; type TDataState = (ddsNormal, ddsNew, ddsModified, ddsDeleted); TBaseClass = class strict protected FID: Integer; FState: TDataState; // jedes Objekt kennt seinen Status public property ID: Integer read FID write FID; property State: TDataState read FState write FState; end; TAddress = class(TBaseClass) strict private FTown: string; FStreet: string; FPostCode: string; FHouseNumber: string; public constructor Create; destructor Destroy; override; property PostCode: string read FPostCode write FPostCode; property Town: string read FTown write FTown; property Street: string read FStreet write FStreet; property HouseNumber: string read FHouseNumber write FHouseNumber; end; TCustomer = class(TBaseClass) strict private FName: string; FAddress: TAddress; FFirstName: string; public constructor Create; destructor Destroy; override; property Name: string read FName write FName; property FirstName: string read FFirstName write FFirstName; property Address: TAddress read FAddress write FAddress; end; TCustomerList = TObjectList<TCustomer>; ...
Delphi-Quellcode:
Unit: FormMain gekürzt
unit Logic.Base;
interface uses Database.Interfaces, Database.Firebird, Database.Events, Logic.DataClasses; type TOnFillCustomerListEvent = procedure(Sender: TObject; List: TCustomerList) of object; TOnGetCustomerEvent = procedure(Sender: TObject; Customer: TCustomer) of object; TOnDataChangedEvent = procedure(Sender: TObject; State: Boolean) of object; TLogic = class strict private FDatabase: IDatabase; FCustomerList: TCustomerList; FOnConnectDatabase: TOnAfterConnectEvent; FOnDisconnectDatabase: TOnAfterDisconnectEvent; FOnDatabaseError: TOnDatabaseErrorEvent; FOnFillCustomerList: TOnFillCustomerListEvent; FOnGetCustomer: TOnGetCustomerEvent; procedure DoOnDatabaseError(Sender: TObject; ErrorNumber: Integer; ErrorMessage: string); procedure DoOnAfterConnect(Sender: TObject); procedure DoOnAfterDisconnect(Sender: TObject); private FDataChanged: Boolean; FOnDataChanged: TOnDataChangedEvent; procedure SetDataChanged(const Value: Boolean); public constructor Create; destructor Destroy; override; property OnConnectDatabase: TOnAfterConnectEvent read FOnConnectDatabase write FOnConnectDatabase; property OnDisconnectDatabase: TOnAfterDisconnectEvent read FOnDisconnectDatabase write FOnDisconnectDatabase; property OnDatabaseError: TOnDatabaseErrorEvent read FOnDatabaseError write FOnDatabaseError; property OnFillCustomerList: TOnFillCustomerListEvent read FOnFillCustomerList write FOnFillCustomerList; property OnGetCustomer: TOnGetCustomerEvent read FOnGetCustomer write FOnGetCustomer; property OnDataChanged: TOnDataChangedEvent read FOnDataChanged write FOnDataChanged; property DataChanged: Boolean read FDataChanged write SetDataChanged; property CustomerList: TCustomerList read FCustomerList; procedure GetCustomerList; procedure GetCustomer(ID: Integer); procedure SaveCustomer(Customer: TCustomer); procedure RefreshCustomerList; end; ... In dieser Unit ist die Form mit den Controls definiert. Die Form gibt der Logic Befehle was sie an Informationen haben möchte. Über Events werden die Information aus der Logik zurückgeliefert und verarbeitet.
Delphi-Quellcode:
unit FormMain;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Actions, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.ActnList, Vcl.ComCtrls, ImageList.Small, Logic.Base, Logic.DataClasses; const conTextGroupboxNormal = 'Details (Normal)'; conTextGroupboxEdit = 'Details (Editmodus)'; type TfoMain = class(TForm) pnlTop: TPanel; pnlContent: TPanel; lvCustomers: TListView; btnNew: TButton; btnCopy: TButton; btnDelete: TButton; grpDetails: TGroupBox; btnSave: TButton; edtName: TEdit; lblName: TLabel; edtFirstName: TEdit; lblFirstName: TLabel; edtPostCode: TEdit; lblPostCode: TLabel; edtTown: TEdit; lblTown: TLabel; edtStreet: TEdit; lblStreet: TLabel; edtHouseNumber: TEdit; lblHouseNumber: TLabel; actlstMain: TActionList; actNew: TAction; btnInfo: TButton; actCopy: TAction; actDelete: TAction; actInfo: TAction; actSave: TAction; actCancel: TAction; btnCancel: TButton; btnMessage: TButton; actMessage: TAction; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); procedure actNewExecute(Sender: TObject); procedure actCopyExecute(Sender: TObject); procedure actDeleteExecute(Sender: TObject); procedure actInfoExecute(Sender: TObject); procedure actSaveExecute(Sender: TObject); procedure actCancelExecute(Sender: TObject); procedure lvCustomersChange(Sender: TObject; Item: TListItem; Change: TItemChange); procedure actMessageExecute(Sender: TObject); private FLogic: TLogic; procedure DoFillCustomerList(Sender: TObject; List: TCustomerList); procedure DoGetCustomer(Sender: TObject; Customer: TCustomer); procedure DoDataChanged(Sender: TObject; State: Boolean); procedure ShowCustomerList(List: TCustomerList); procedure ShowCustomer(Customer: TCustomer); procedure SetCustomerToEdit(Active: Boolean); procedure SetButtons(Active: Boolean); public end; var foMain: TfoMain; ... Prinzip des Datenholens:
Delphi-Quellcode:
Prinzip der Speicherung
procedure TDatabaseFirebird.Get(Customer: TCustomer; ID: Integer); // nur einen Customer holen
var Qry: TUniQuery; begin Qry := CreateQuery; // Query incl. der Connection erzeugen try // SQL wie gehabt Qry.SQL.Text := 'SELECT * FROM T_CUSTOMER WHERE ID = :ID'; // Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen Qry.ParamByName('ID').AsInteger := ID; Qry.Open; // das Objekt füllen Customer.ID := Qry.FieldByName('ID').AsInteger; Customer.Name := Qry.FieldByName('F_NAME').AsString; Customer.FirstName := Qry.FieldByName('F_FIRST_NAME').AsString; // Alternative für GET wäre ein JOIN im Statement und die Adresse hier zusammenbauen. // Der Vorteil der Trennung: Man kann auch die Adresse seperat lesen. Wie man es braucht... :-) Get(Customer.Address, Qry.FieldByName('F_ADDRESS_ID').AsInteger); Customer.State := ddsNormal; // Wichtig: Status setzen finally Qry.Free; end; end; ... procedure TDatabaseFirebird.FillList(List: TCustomerList); // komplette Liste füllen var Qry: TUniQuery; Customer: TCustomer; begin List.Clear; Qry := CreateQuery; // Query incl. der Connection erzeugen try Qry.SQL.Text := 'SELECT * FROM T_CUSTOMER'; // Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen Qry.Open; while not Qry.Eof do begin Customer := TCustomer.Create; // Objekt erzeuggen Get(Customer, Qry.FieldByName('ID').AsInteger); // Objekt füllen List.Add(Customer); // Objekt in Liste legen Qry.Next; end; finally Qry.Free; end; end;
Delphi-Quellcode:
Prinzip der Datenanzeige
function TDatabaseFirebird.Save(Customer: TCustomer): Integer; // Speichern
var Qry: TUniQuery; begin Result := -1; Qry := CreateQuery; try StartTransaction; try case Customer.State of // entsprechend dem Status des Objektes ddsNew: // insert begin Customer.Address.ID := Save(Customer.Address); // Rückgabe der ID als Erstes wegen ID Qry.SQL.Text := 'INSERT INTO T_CUSTOMER (F_NAME, F_FIRST_NAME, F_ADDRESS_ID) VALUES (:NAM, :FIN, :ADD) returning ID'; // Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen // das Objekt dem SQL übergeben Qry.ParamByName('NAM').AsString := Customer.Name; Qry.ParamByName('FIN').AsString := Customer.FirstName; Qry.ParamByName('ADD').AsInteger := Customer.Address.ID; Qry.ExecSQL; Customer.ID := Qry.ParamByName('RET_ID').AsInteger; Customer.State := ddsNormal; Result := Customer.ID; end; ddsModified: // update begin Qry.SQL.Text := 'UPDATE T_CUSTOMER SET F_NAME = :NAM, F_FIRST_NAME = :FIN, F_ADDRESS_ID = :ADD WHERE ID = :ID'; // Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen // das Objekt dem SQL übergeben Qry.ParamByName('ID').AsInteger := Customer.ID; Qry.ParamByName('NAM').AsString := Customer.Name; Qry.ParamByName('FIN').AsString := Customer.FirstName; Qry.ParamByName('ADD').AsInteger := Customer.Address.ID; Qry.ExecSQL; Save(Customer.Address); Customer.State := ddsNormal; Customer.Address.State := ddsNormal; Result := Customer.ID; end; ddsDeleted: // deleted begin Qry.SQL.Text := 'DELETE FROM T_CUSTOMER WHERE ID = :ID'; // Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen Qry.ParamByName('ID').AsInteger := Customer.ID; Qry.ExecSQL; Customer.Address.State := ddsDeleted; Save(Customer.Address); Result := Customer.ID; end; end; Commit; except Rollback; end; finally Qry.Free; end; end;
Delphi-Quellcode:
Erweiterungen:
procedure TfoMain.DoFillCustomerList(Sender: TObject; List: TCustomerList); // Event nach dem Datenholen
begin ShowCustomerList(List); SetCustomerToEdit(False); end; ... procedure TfoMain.ShowCustomerList(List: TCustomerList); var Item: TListItem; Customer: TCustomer; begin lvCustomers.Items.Clear; for Customer in List do begin Item:= lvCustomers.Items.Add; Item.Data:= Customer; // Das Objekt (Pointer) hängt an dem Eintrag Item.SubItems.Add(Customer.Name); Item.SubItems.Add(Customer.FirstName); Item.SubItems.Add(Customer.Address.Town); Item.ImageIndex:= dmSmall.GetIconIndexDataState(Customer.State); end; lvCustomers.Items.Item[0].Selected := True; // ersten Eintrag markieren...oder so end; Nach Bedarf können u.a. Funktionen hinzugefügt oder mit einander kombiniert werden. (DRY) Vorteile: * Keine datensensitiven Controls. Das bedeutet Unabhängigkeit von der Optik der DB sensitiven Controls. * Eine Property des Objektes kann z.B. in einem TEdit einem TMemo oder mit einem TRotMitGelbenPunktenControl dargestellt werden. * Alle SQL Statements auf einem Fleck. Das erleichtert das Suchen nach einem Statement. Die SQL sind nicht mehr auf den gesamten QT verteilt. * Die Umbauten bei Datenbankwechsel beziehen sich nur auf das Interface. * Durch die Objekte kann man sich die Informationen beliebig zustammenstellen. Auch wenn sie auch verschieden Tabelle stammen. * Speichern mit einem Einzeiler
Delphi-Quellcode:
* Objekte sind besser debugbar.
FDatabase.Save(Customer);
... * Objekte können wiederum Listen mit Objekten enthalten. * Objekte sind mit einem Rutsch, über das Database Interface, speicherbar. Bei diesem Tutorial geht es ums Prinzip bei der Arbeit mit Objekten ohne die üblichen Verdächtigen der großen Frameworks für Datenbanken. Meistens lohnt der Aufwand nicht ein großes Framework zu installieren. Auch der Einarbeitungsaufwand bei diesen ist nicht ohne... Manchmal ist weniger mehr. Diskussion eröffnet. PS: Alle Fehler sind urheberrechtlich geschützt weil Unikate. Geändert von haentschman (27. Jul 2017 um 15:01 Uhr) |
Online
Delphi 12 Athens |
#11
Moin...
Zitat:
Danke für das Tutorial.
Zitat:
Erst einmal vielen Dank!
Zitat:
Der Spass fängt aber dann an wenn du ein Grid oder Listview scrollen und editieren möchtest,
Zitat:
Wie würdest du denn so etwas bei deinem Vorschlag lösen ?
Zitat:
Das müsste ja meiner Meinung nach auch gekapselt werden, das will man nicht immer wieder neu schreiben müssen.
...aber das würde zu weit führen und hat nichts mit dem Thema zu tun.
Zitat:
aber das wären nur Detailänderungen, die mir pers. besser in den Kram passen würden.
Zitat:
sollte immer die (formal) gleiche Liste liefern.
Zitat:
Mit einem TDataModule kommt man (ich) genauso weit, einziges Problem(?) für jede DB brauch ich ein eigenes Modul
Delphi-Quellcode:
...die Vorteile von Interfaces wurde schon an anderer Stelle diskutiert. http://www.delphipraxis.net/192364-t...nterfaces.html
// Klassendefinition oder so ähnlich
TDataBaseAbstract = class public procedure Blubb; abstract; end; ... TDataBase1 = class(TDataBaseAbstract) public procedure Blubb; override; // die spezielle Implementierung für Blubb end; ... TDataBase2 = class(TDataBaseAbstract) public procedure Blubb; override; // die spezielle Implementierung für Blubb end; // Instanz FDatabase: TDataBaseAbstract; ... FDatabase := TDataBase2.Create; // oder so... Geändert von haentschman (28. Jul 2017 um 16:27 Uhr) |
Zitat |
FreePascal / Lazarus |
#12
Prinzipiell kommst du auch mit einem DataModule für eine Datenbank zurecht. Wenn du ein neues DBMS dazunimmst, kommst du um eine Abstraktion nicht herum.
Gruß K-H |
Zitat |
Online
Delphi 12 Athens |
#13
Hallöle...
Zitat:
Danke, das hätte man mir ja auch gleich so erklären können
|
Zitat |
Delphi 11 Alexandria |
#14
Hallo, Vorweg: Das Tutorial ist gut gelungen auch wenn da mehr Code gezeigt wird als das Code erklärt wird.
Neugierig wie ich bin plus DB Neuling habe ich mir das Projekt geladen und beim Start der .exe erscheint das (gekürzt aufs wesentliche):
Zitat:
executable : Tutorial.exe
exec. date/time : 2017-07-27 14:01 version : 1.0.0.0 compiled with : Delphi 10.1 Berlin madExcept version : 4.0.16 callstack crc : $0c5e2cf1, $23db6709, $23db6709 exception number : 1 exception class : EAccessViolation exception message : Zugriffsverletzung bei Adresse 007FF967 in Modul 'Tutorial.exe'. Lesen von Adresse 00000008. main thread ($11f8): 007ff967 +00b Tutorial.exe Logic.Base 143 +2 TLogic.GetCustomerList 00800a6e +026 Tutorial.exe FormMain 210 +2 TfoMain.FormShow 0065a34d +015 Tutorial.exe Vcl.Forms TCustomForm.DoShow 0065ebb9 +0a9 Tutorial.exe Vcl.Forms TCustomForm.CMShowingChanged 005a700e +2be Tutorial.exe Vcl.Controls TControl.WndProc 005abb59 +5e9 Tutorial.exe Vcl.Controls TWinControl.WndProc 0065ae0d +64d Tutorial.exe Vcl.Forms TCustomForm.WndProc 005a6c48 +024 Tutorial.exe Vcl.Controls TControl.Perform 005aaf21 +10d Tutorial.exe Vcl.Controls TWinControl.UpdateShowing 005ab030 +0bc Tutorial.exe Vcl.Controls TWinControl.UpdateControlState 005adc2a +026 Tutorial.exe Vcl.Controls TWinControl.CMVisibleChanged 005a700e +2be Tutorial.exe Vcl.Controls TControl.WndProc 005abb59 +5e9 Tutorial.exe Vcl.Controls TWinControl.WndProc 0065ae0d +64d Tutorial.exe Vcl.Forms TCustomForm.WndProc 005a6c48 +024 Tutorial.exe Vcl.Controls TControl.Perform 005a55fa +026 Tutorial.exe Vcl.Controls TControl.SetVisible 0065a629 +03d Tutorial.exe Vcl.Forms TCustomForm.SetVisible 00664897 +0b3 Tutorial.exe Vcl.Forms TApplication.Run 0080e9d9 +061 Tutorial.exe Tutorial 25 +5 initialization 77533675 +010 kernel32.dll BaseThreadInitThunk thread $12f4: 77cd00f6 +0e ntdll.dll NtWaitForMultipleObjects 77533675 +10 kernel32.dll BaseThreadInitThunk thread $1128: 77cd1edf +0b ntdll.dll NtWaitForWorkViaWorkerFactory 77533675 +10 kernel32.dll BaseThreadInitThunk thread $104c: 77cd1edf +0b ntdll.dll NtWaitForWorkViaWorkerFactory 77533675 +10 kernel32.dll BaseThreadInitThunk thread $afc: 77cd1edf +0b ntdll.dll NtWaitForWorkViaWorkerFactory 77533675 +10 kernel32.dll BaseThreadInitThunk modules: 00400000 Tutorial.exe 1.0.0.0 \Win32 10000000 fbclient.dll 2.5.1.26351 \Win32 4a800000 icuuc30.dll 3.0.0.0 \Win32 4ad00000 icudt30.dll 3.0.0.0 \Win32 disassembling: [...] 007ff95d mov ebp, esp 007ff95f push ecx 007ff960 push ebx 007ff961 mov [ebp-4], eax 007ff964 143 mov eax, [ebp-4] 007ff967 > mov edx, [eax+8] 007ff96a mov eax, [ebp-4] 007ff96d mov eax, [eax+4] 007ff970 mov ecx, [eax] 007ff972 call dword ptr [ecx+$3c] 007ff972 [...] |
Zitat |
Online
Delphi 12 Athens |
#15
Moin...
Da ich auf der Arbeit kein UniDAC habe, kann ich es erst am Wochenende nachschauen. Aber normalerweise gibt es keine Voraussetzungen als die EXE im "out" Ordner zu starten. Nachtrag:
Zitat:
da mehr Code gezeigt wird als das Code erklärt wird.
Geändert von haentschman (24. Mai 2018 um 07:30 Uhr) |
Zitat |
Online
Delphi 12 Athens |
#17
Zitat:
007ff967 +00b Tutorial.exe Logic.Base 143 +2 TLogic.GetCustomerList
Delphi-Quellcode:
procedure TLogic.GetCustomerList;
begin // Daten holen und in die übergebene Liste ablegen FDatabase.FillList(FCustomerList); // <- 143 FCustomer List ist instanziert DataChanged := False; // Setter // Liste per Event übergeben if Assigned(FOnFillCustomerList) then begin FOnFillCustomerList(Self, FCustomerList); end; end;
Delphi-Quellcode:
constructor TLogic.Create;
begin FDataChanged := False; // Customer Liste erstellen FCustomerList := TCustomerList.Create(True); // Instanz // Datenbank Interface FDatabase := TDatabaseFirebird.Create; // An diesem Punkt wird das Interface gewechselt auf ein anderes DBMS z.b. entsprechend der Einstellungen in der INI/XML usw. // Eventhandler einhängen FDatabase.OnAfterConnect := DoOnAfterConnect; FDatabase.OnAfterDisconnect := DoOnAfterDisconnect; FDatabase.OnDatabaseError := DoOnDatabaseError; FDatabase.Connect; // ggf. Prüfung auf Rückgabewert (Connected) end; destructor TLogic.Destroy; begin FCustomerList.Free; // die enthaltenen Objekte werden automatisch weggeräumt. // Keine Freigabe des Interfaces nötig. :-) inherited; end; Geändert von haentschman (24. Mai 2018 um 08:10 Uhr) |
Zitat |
Delphi 11 Alexandria |
#18
Wenn man das Programm ausführt, kommt der Fehler bei mir auch. Selberkompiliert funktioniert es, nachdem ich die Datenbankverbindung auf embedded umgestellt habe.
FConnection.Server := ''; //'firma-server/3025'; // Embedded
Markus Kinzler
|
Zitat |
Online
Delphi 12 Athens |
#19
Echt jetzt? Zu meiner Verteidigung...ich arbeite nie mit Embedded.
Zitat:
'firma-server/3025'; // Embedded
@mkinzler: Danke. Geändert von haentschman (24. Mai 2018 um 08:33 Uhr) |
Zitat |
Delphi 11 Alexandria |
#20
Danke mkinzler, Deine .exe kann ich Starten!
Ich habe soeben Versucht das Projekt mit Tokyo zu öffnen = Package PngComponents fehlte mir, hab das von Uwe Raabe geladen und installiert also öffnen lässt es sich jetzt ohne Probleme. Jetzt das nächste mir fehlende, Uni.pas. Ich vermute UniDAC ist damit gemeint und hier meine Frage: Reicht da die Express oder muss ich die Pro Version nehmen? (ich = planlos da Neuling) Vielen Dank für Hilfe! Das MadExcept aus der .dpr habe ich auskommentiert, reicht das aus oder muss ich MadExcept dafür auch laden und installieren? |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |