![]() |
Datenbank: Firebird • Version: 2.5 • Zugriff über: FireDAC
OnNewRecord nicht aufgerufen
Hallo,
hat jemand eine Ahnung, warum mein per Code zugewiesener OnNewRecord Handler im Ablauf des FireDAC BatchMove.Execute nie aufgerufen wird? Für keine der zu kopierenden Tabellen. Daten werden aber kopiert.
Delphi-Quellcode:
Woran könnte das liegen?
FWriter : TFDBatchMoveSQLWriter;
... constructor TDBCopy.Create; begin inherited; ... FWriter := TFDBatchMoveSQLWriter.Create(FBatchMove); FBatchMove.Reader := FReader; FBatchMove.Writer := FWriter; OpenSQLConnection(FSourceSQLConnection, SourceDBName); OpenSQLConnection(FTargetSQLConnection, TargetDBName); FReader.Connection := FSourceSQLConnection; FWriter.Connection := FTargetSQLConnection; FWriter.FDDataSet.OnNewRecord := OnNewRecord; end; procedure TDBCopy.OnNewRecord(DataSet: TDataSet); begin // Code hier drin wird definitiv nicht aufgerufen... end; Grüße TurboMagic |
AW: OnNewRecord nicht aufgerufen
Ein
Delphi-Quellcode:
legt keinen neuen Datensatz im DataSet an sondern führt ein SQL INSERT aus. Damit gibt es auch kein
TFDBatchMoveSQLWriter
Delphi-Quellcode:
.
OnNewRecord
|
AW: OnNewRecord nicht aufgerufen
Nebenbei: Wenn du eine inhaltlich gleiche Frage an verschiedenen Stellen (DP, DP-EN, SO) stellst, wäre es schön das jeweils anzugeben. Dann kann man an den jeweiligen Stellen nachschauen ob schon jemand eine passende Antwort gegeben hat. Vielleicht reicht ja auch schon eine Stelle für die Frage um die Threads zum Thema zusammenzuhalten.
|
AW: OnNewRecord nicht aufgerufen
Hallo,
danke für die Info und Sorry, dass ich nicht auf den anderen Post hingewiesen hatte. Wenn ich dich richtig verstehe, dann sollte ich für den Writer keinen SQL Writer benutzen sondern den DataSetWriter benutzen. Der müsste dann in dem Event mittels FieldByName auf die Spalte zugreifen können. In deinem anderen Ansatz mit OnWriteRecord hab' ich noch nicht wirklich verstanden gehabt wie ich an die nötigen Details ran komme um den gewünschten Wert eintragen zu können. Grüße TurboMagic |
AW: OnNewRecord nicht aufgerufen
Ok, das reine austauschen der Typdeklaration auf den TFDBatchMoveDataSetWriter
(und anpassen des Create Aufrufes) hilft nich, da dieser Writer keine .TableName Eigenschaft hat. Wie muss ich damit umgehen? Muss ich dem ein eigenes DataSet zuweisen? Falls ja was für eines und wie damit umgehen? Ich hab' bisher immer FDQuery Datasets benutzt. Grüße TurboMagic PS: der Post in der EN DP ist hier: ![]() |
AW: OnNewRecord nicht aufgerufen
Du kannst dem TFDBatchMoveDataSetWriter ja ein TFDTable zuordnen - das hat dann wiederum ein Property TableName.
Allerdings sind das alles nur Hinweise. Konkret habe ich das selbst auch noch nicht probiert. Wenn das NOT NULL Feld in der Datenbank einen Default-Wert hat oder über eine Sequenz gefüllt wird, dann sollte ein INSERT auch ohne einen Wert für dieses Feld gehen. In dem Fall wird das Feld im Server passend belegt. Ich weiß ja auch nicht, mit welchem Wert du das Feld belegst, wenn du es in einem der Events beschreiben würdest. In dem Beispiel in der DP-EN wird es ja mit 0 vorbelegt - das könnte man auch direkt im Server so festlegen (siehe ![]() |
AW: OnNewRecord nicht aufgerufen
Wenn im generierten "INSERT"-Statement explizit einem Feld NULL übergeben wird, dann wird bei den meisten DBMS auch NULL in die Tabelle geschrieben.
Der "DEFAULT"-Wert wird vom DBMS nur verwendet, wenn das Feld nicht im Statement vorkommt, oder dort explizit DEFAULT übergeben wird. Ich weiß nicht, ob FieDAC, bzw. der TFDBatchMoveDataSetWriter Letzteres kann. ![]() Hier werden ja mit einem Statement mehrere Records übergeben und somit stünde ein Feld immer im Statement, sobald es mindestens einmal einen Wert enthält. (also falls/da nicht jeder Datensatz einzeln übergeben würde) Beim normalen Query.Post, lassen viele DB-Komponenten die Felder mit NULL weg, wenn sie das INSERT-Statement generieren. PS: Bei uns werden im AfterInsert meistens die Default-Werte von der DB abgerufen und in die DataSet.Fields eingetragen, damit die Nutzer Default-Werte bereits im Programm sehen, während des Ausfüllens der restlichen Edits. (dort greift dann auch beim Insert nicht mehr das DEFAULT der Datenbank, da bereits Daten in den Feldern drin stehen) |
AW: OnNewRecord nicht aufgerufen
Wie wäre es denn mit simplen Datenbanktriggern? (Die kannste ja nach dem Befüllen der Tabellen wieder wegwerfen.)
SQL-Code:
Und das Schöne daran ist, es ist vollkommen wurscht, auf welchem Weg die Daten in die Datenbank kommen, werden Werte für andere Felder benötugt, einfach die Trigger anpassen.
CREATE TRIGGER TR_KASSE_EINSTELLUNGEN_BI FOR KASSE_EINSTELLUNGEN ACTIVE before insert POSITION 0 AS
BEGIN if (NEW.DRAWBACK_CALCULATION is NULL) then NEW.DRAWBACK_CALCULATION = 0; END CREATE TRIGGER TR_KASSE_PRINTSETTINGS_BI FOR KASSE_PRINTSETTINGS ACTIVE before insert POSITION 0 AS BEGIN if (NEW.PRINT_SMALL_BONS is NULL) then NEW.PRINT_SMALL_BONS = 0; END Sinnvoll ist es übrigens, Spalten, für die keine Werte bekannt sind, nicht mit ins Insert zu packen, sondern sie von der Datenbank per Defaultwert und/oder Trigger befüllen zu lassen. Das sind nun mal halt Aufgaben, die Datenbanken von Haus aus können, egal ob die Daten über ein Delphiprogramm oder Flamerobin oder ISQL, oder welche Datenbanksoftware gerade genutzt wird, ... in die Datenbank kommen. Da muss man sich nicht zwingend erstmal 'ne Software schreiben, die das dann "irgendwie" (hoffentlich verlässlich) übernimmt. |
AW: OnNewRecord nicht aufgerufen
Sobald ich die Zeit dazu finde muss ich mir das mit den Defaultwerten nochmal anschauen.
Evtl. hatte ich da einfach beim Testen noch was falsch gemacht im Ablauf. |
AW: OnNewRecord nicht aufgerufen
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
habe mir das mit dem not NULL nochmal angeschauen, bin aber verwundert, dass es nicht klappt. Im Anhang ein Screenshot eines DB Verwaltungstools, der zeigt, dass ich genau vor dem Öffnen DB Verbindungen der Reader und Writer des Batch Move mit dem Tool für diese not Null Spalte definiert habe, dass der Standardwert 0 sein soll (KASSE_BOOLEAN ist ein Smallint). Und ja, ich habe diese Änderung auch Compiliert (so nennt das Tool das). => warum bekomme ich trotzdem diese Exception? :o Grüße TurboMagic |
AW: OnNewRecord nicht aufgerufen
Wie wäre es, wenn jemand auf die abwegige Idee käme, mal zu schauen, was da eigentlich gemacht wird?
* So manches DBMS bietet es serverseitig an, ein Logging zu aktivieren. * oder eben im Client loggen TFDBatchMove bietet paar entsprechende Property an. (LogFileAction und LogFileName) sowie ![]() |
AW: OnNewRecord nicht aufgerufen
Hallöle...8-)
Zitat:
:wink: |
AW: OnNewRecord nicht aufgerufen
Zitat:
Beziehst du dich auf das Lesen oder das reinschreiben? Mein Szenario ist ja, dass ich aus einer Datenbankdatei eine Zeile Lese (die betrffende Tabelle hat wirklich nur eine Zeile), der Spalten fehlen, die in der Ziel DB-Datei neu hinzugekommen sind und die dort als "not NULL" deklariert sind. So wie ich FBBatchMove eingestellt habe muss es aus der Ziel DB erstmal alle Sätze dieser Tabelle löschen (falls es welche gibt). Der zu kopierende Datensatz muss also für die Ziel DB neu sein und damit meiner Meinung nach dieser Default Wert reingeschrieben werden, da die QUelldaten ja dafür keinen Wert haben. Oder wo liege ich da jetzt falsch? Grüße TurboMagic |
AW: OnNewRecord nicht aufgerufen
Hallo,
hab' jetzt mal so ein Protokoll anfertigen lassen, nur hat mir das auch nicht mehr gesagt als das, was ich schon wusste :-( Es ist auch recht platzverschwednerisch formatiert und wo da keine Fehler gefunden wurden wird auch nicht klar, weil die Leider keinen Tabellennamen reingeschrieben haben. Aber ja, nicht alles ist eine Tabelle für Batch Move. Hier der relevante Teil des Logs in der originalen Formatierung:
Code:
Grüße
*************** Protokoll starten 03.12.2023 10:17:04 ***************
********** Keine Fehler protokolliert ********** *************** Protokoll beenden 03.12.2023 10:17:04 *************** *************** Protokoll starten 03.12.2023 10:17:04 *************** [FireDAC][Phys][FB]validation error for column "KASSE_EINSTELLUNGEN"."DRAWBACK_CALCULATION", value "*** null ***" INSERT INTO KASSE_EINSTELLUNGEN (PWD, IS_LOCKED, INIT_WIZARD_RUN, CAN_SKIP_TSE, DRAWBACK_CALCULATION) VALUES (:PWD, :IS_LOCKED, :INIT_WIZARD_RUN, :CAN_SKIP_TSE, :DRAWBACK_CALCULATION) *************** Protokoll beenden 03.12.2023 10:17:07 *************** *************** Protokoll starten 03.12.2023 10:17:07 *************** ********** Keine Fehler protokolliert ********** *************** Protokoll beenden 03.12.2023 10:17:07 *************** TurboMagic |
AW: OnNewRecord nicht aufgerufen
Zitat:
Dagegen ein Neues Feld, welches es vorher noch nicht gab, und das nicht ans Ziel übergibt, es also nicht im INSERT vorkommt, da nimmt die DB dann das DEFAULT. Zitat:
|
AW: OnNewRecord nicht aufgerufen
Soweit ich weiß, vergibt die Datenbank den Defaultwert nur dann, wenn eine Spalte im Insert nicht angegeben wird.
Wenn also DRAWBACK_CALCULATION Not Null ist und Du keinen Wert dafür hast, dann darfst Du für DRAWBACK_CALCULATION auch nicht im Insert Null übergeben. Beim Weglassen der Spalte im Insert übernimmt das dann die Datenbank, indem der Defaultwert in DRAWBACK_CALCULATION geschrieben wird.
SQL-Code:
INSERT INTO KASSE_EINSTELLUNGEN
(PWD, IS_LOCKED, INIT_WIZARD_RUN, CAN_SKIP_TSE) VALUES (:PWD, :IS_LOCKED, :INIT_WIZARD_RUN, :CAN_SKIP_TSE) |
AW: OnNewRecord nicht aufgerufen
Hallo,
1. In der Quell DB gibt's die entsprechende Spalte noch gar nicht. Was FireDAC beim Einfügen damit anstellt kann ich jedoch mangels Quellcode in der Pro Version nicht nachschauen. 2. Somit habt ihr alle irgendwie recht, auch wenn mir das nicht so ganz hilft. Aber: 3. Ich habe jetzt eine funktionierende Lösung! Der Hinweis von Uwe, dass TFDTable das OnNewRecord event aufruft und ich statt eines SQL Writers einfach einen DatasetWriter mit zugewiesenem TFDTable benutzen könnte hat zum Erfolg geführt. Im OnNewRecord prüfe ich jetzt, ob die entsprechende Spalte der entsprechenden Tabelle NULL ist und falls ja, weise ich den Defaultwert zu. Jetzt muss ich nur noch den Code ein wenig aufräumen, weil das ja bisher nur testweise kurz eingebaut wurde. ;-) Grüße TurboMagic |
AW: OnNewRecord nicht aufgerufen
Wenn nun für das INSERT ein TFDTable genutzt wird, und das beim INSERT-Statement dann die NULL-Felder weg lässt, dann sollte doch direkt das DBMS den DEFAULT benutzen?
Oder geht vielleicht auch ein TFDQuery? |
AW: OnNewRecord nicht aufgerufen
Mit dem TFDBatchMoveSQLWriter würde es auch gehen, wenn du dessen WriteSQL Property bei jeder der betroffenen Tabelle passend angeben würdest. Bleibt das Property leer wird ein SQL automatisch erzeugt. Dabei werden die NOT NULL Felder als required erkannt und in das INSERT aufgenommen, was eine Zuweisung zu dem Feldwert erzwingt.
|
AW: OnNewRecord nicht aufgerufen
Zitat:
Nur: dann ist ja der "Gag" weg, dass einem das System was automatisch abnimmt ;-) Zumindest für Spalten die nicht als "not Null" deklariert sind. Man müsste dann nämlich bei jeder Änderung das SQL anpassen, sonst fehlen die Daten nach dem Update ;-) |
AW: OnNewRecord nicht aufgerufen
Zitat:
Eine weitere Alternative wäre übrigens das Anlegen eines Mappings mit dem Namen der Target-Column als DestinationFieldName und dem Defaultwert als SourceExpression, während SourceFieldName natürlich leer bleiben muss. Aber auch dass muss gegebenenfalls per Tabelle definiert werden. Du musst halt schauen, welcher Ansatz den besten Mix aus Performance und geringem Maintenance-Aufwand bietet. |
AW: OnNewRecord nicht aufgerufen
Leider beachten viele DB-Komponenten nur das NOT NULL, aber kennen kein DEFAULT,
drum wollen sie zwanghaft bei "Required" (NOT NULL) etwas übergeben, bzw. werfen bösartig im BeforePost gern eine Exception. JA, bei Required / NOT NULL muß letztendlich ein Wert vorhanden sein, aber der darf auch aus einem DEFAULT kommen. |
AW: OnNewRecord nicht aufgerufen
Moin...😎
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:24 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz