Autor |
Beitrag |
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: So 27.06.21 11:28
Ein freundliches Hallo an alle,
ich möchte in einer ADO Datenbank einen leeren Datensatz erzeugen und anschließend die Daten aus einer Tabelle einsetzen.
Zum Testen verwende ich die Kunden-Tabelle von Nordwind. Ich lese die Daten der Tabelle in ein StringGrid ein. Dort füge ich eine Zeile ein, füge Daten hinzu und möchte diesen Datensatz speichern. Dazu wird die Tabelle in "ADORecordSet" geladen.
Mit "ADORecordSet.AddNew(0, null);" erhalte ich die Fehlermeldung F1 im Anhang.
Mit "ADORecordSet.AddNew(null,null);" erhalte ich die Fehlermeldung F2 im Anhang.
Gibt es eine Möglichkeit einen leeren Datensatz zu erzeugen, auch wenn für die Spalte Daten verpflichtend sind, oder muß ich die Daten gleich mitliefern? Ein Beispiel wäre schön, hab noch nichts passende gefunden.
Ich verwende Delphi4
Grüße von der sonnigen Nordsee
Peter
Einloggen, um Attachments anzusehen!
|
|
Th69
Beiträge: 4791
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: So 27.06.21 11:52
Wenn die Spalten einer DB-Tabelle als "required" ( not null) gekennzeichnet sind, dann müssen selbstverständlich dort auch Daten geliefert werden (außer es wurden Default-Werte beim Anlegen mitgegeben).
Aber warum möchtest du denn überhaupt leere Datensätze erzeugen (anstatt gleich den korrekten Datensatz abzuspeichern)?
Und warum verwendest du kein TDBGrid?
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: So 27.06.21 12:16
Hallo Th69,
Dank Dir für die Antwort. Ich verwende TStringGrid, weil mit dem gleichen Objekt auch andere Datenquellen wie Textdateien gelesen werden.
Grüße von der immer noch sonnigen Nordsee
Peter
|
|
Ralf Jansen
Beiträge: 4706
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: So 27.06.21 12:33
Um sich von den Regeln der DB oder sonstiger anderen Schichten zu entkoppeln hilft es ein anderes Dataset dazwischenzuschalten um Kontrolle zu haben wann denn was passiert.
Das letztes mal als ich Delphi programmiert habe war das ein TClientDataset. Möglicherweise gibt's da mittlerweile was anders mit ähnlichem Verhalten.
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: So 27.06.21 12:52
hallo Ralf,
Dank auch Dir. "TClientDataset" sieht mir nach DAO aus, zumindest in Delphi4. Bietet ADO keine Möglichkeit den direkten Weg zu gehen?
Grüße von der sonnigen Nordsee
Peter
|
|
Ralf Jansen
Beiträge: 4706
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: So 27.06.21 14:32
Möglicherweise. Aber das was du bisher schreibst kommt bei mir da sehr widersprüchlich an.
Du sagst an einer Stelle das du es so machst wie du es machst um verschiedene Quellen benutzen zu können. Und jetzt fragst du nach direkt per ADO.
Was denn jetzt. (Fast) beliebige Datenquellen oder nur ADO Quellen?
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Mo 28.06.21 10:06
Hallo Ralf.
Wo sind da Widersprüche???
Andere Quellen wie z.B. DAO oder Text funktionieren bereits! Bei ADO klappt es noch nicht!!
Aber zurück zu meiner Frage!!!!
Gibt es eine Möglichkeit einen leeren Datensatz zu erzeugen, auch wenn für die Spalte Daten verpflichtend sind, oder muß ich die Daten gleich mitliefern?
Grüße von der wieder sonnigen Nordsee
Peter
|
|
Th69
Beiträge: 4791
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Mo 28.06.21 10:48
Das habe ich dir doch in meinem ersten Satz meiner Antwort geschrieben (dafür ist doch die Datenbank-Integrität da, damit keinen unvollständigen Datensätze eingetragen werden können ).
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Mo 28.06.21 11:13
Hallo Th69,
Ganz tolle Antwort!!!!!!!!!!!!!!!!
Was bringt mir das???? Ich würde hier nicht so dumme Fragen stellen, wenn ich eine Alternative gefunden hätte! Die hätte ich längst getestet!!!
Inzwischen habe ich aber auch die Methode "AppendRecord" gefunden. Ich forsche noch daran, wie die Parameter aussehen müssen.
Peter
|
|
Sinspin
Beiträge: 1334
Erhaltene Danke: 118
Win 10
RIO, CE, Lazarus
|
Verfasst: Mo 28.06.21 14:36
Peter18 hat folgendes geschrieben : | Gibt es eine Möglichkeit einen leeren Datensatz zu erzeugen, auch wenn für die Spalte Daten verpflichtend sind, oder muß ich die Daten gleich mitliefern? |
Nein.
Natürlich auch unabhängig davon wieviele Ausrufezeichen du uns vor die Nase setzt.
_________________ Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
|
|
jaenicke
Beiträge: 19289
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 28.06.21 16:06
Die einzig sinnvolle Variante ist, wenn du das Verhalten deines StringGrids an das des DBGrids anpasst, sprich zwar eine Zeile mit Append anlegst, aber man die Zeile erst bei sinnvollen Eingaben verlassen kann, damit dann ein Post erfolgen kann...
Peter18 hat folgendes geschrieben : | Ich verwende TStringGrid, weil mit dem gleichen Objekt auch andere Datenquellen wie Textdateien gelesen werden. |
Die für den Anwendungszweck passende Komponente dynamisch zu erzeugen, hielte ich für sinnvoller. Dann könntest du die eingebauten Funktionen eines DBGrids auch nutzen, wenn eine Datenbank angebunden ist. Wenn du die Zugriffe darauf kapselst, sollte das für die restliche Logik kein Problem sein.
Ralf Jansen hat folgendes geschrieben : | Das letztes mal als ich Delphi programmiert habe war das ein TClientDataset. Möglicherweise gibt's da mittlerweile was anders mit ähnlichem Verhalten. |
In aktuellen Delphiversionen gibt es Datasets im Speicher auch ohne TClientDataset, da FireDAC diese direkt mitbringt.
Das wäre natürlich auch eine sinnvolle Lösung, wenn auch etwas aufwendiger, egal ob mit Delphi 4 und TClientDataSet oder FireDAC.
|
|
Blup
Beiträge: 174
Erhaltene Danke: 43
|
Verfasst: Di 29.06.21 11:25
Wenn du beim Import direkt mit der Datenbank arbeiten willst, dann erstelle für diesen Anwendungfall eine eigene Tabelle ohne direkte Abhängigkeiten.
Das können dort auch alles Textfelder sein, die direkt durch den konkreten Import(ADO, CSV, ...) erst ein mal gefüllt werden.
Danach kannst du die einzelnen Datensätze im Grid bearbeiten und validieren.
Wenn alles ok ist, folgt als letzter Schritt die Übernahme der Daten in die richtige(n) Tabelle(n).
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Di 06.07.21 10:56
Hallo Sinspin,
auch eine ganz tolle Antwort!!!!!!!!!!!!!!
ein NEIN auf eine oder Frage, die auch noch zitiert wurde! Wie ich das sehe ist ein Forum wie dieses dazu da, denen, die ein Problem haben, zu helfen es zu lösen! Daher die Ausrufezeichen!!
Wenn ich die richtige Frage wüßte oder das richtige Stichwort, so hätte ich sicher schon im Internet eine Lösung gefunden. Hab ich aber nicht, daher hier meine Frage! Zudem sind die Beschreibungen zu meinem Delphi und die Quellen sehr dürftig.
Hallo jaenicke, hallo Blup,
ich habe eine ähnliche Schnittstelle zu DAO und würde nur ungern alles komlett neu machen. Aber vielleichtkönnt Ihr mir trotzdem weiterhelfen.
Ich habe ein "ADO DataSet component" im Internet gefunden. Da scheint aber noch eine Macke drin zu sein. Ich vermute, das Problem liegt in einer virtuellen Routine, damit habe ich aber noch nicht programmiert.
Ich habe nun "AppendRecord" in mein Programm eingebaut und die Daten als Array übergeben. Egal, ob ich "AppendRecord" oder "Append" aufrufe lande ich in der Routine
"procedure TADODataSet.InternalInitRecord(Buffer: PChar);".
dort wird
"ADORecordSet.AddNew(0, null);"
aufgerufen und führt zu einem Fehler. Im Parameter "Buffer: PChar" ist aber nur ein Buchstabe zu finden, eventuell ein Pointer. Unter uses stehen: Windows, SysUtils, Classes, Db, ADODB_TLB, OleCtrls;. Die Dateien Db.pas, ADODB_TLB.pas und OleCtrls.pas fehlen mir. Ich kann also nicht nachvollziehen, warum ich mit Append und AppendRecord in der gleichen Routine lande.
Vielleicht kann mir jemand zeigen wo der Hund begaben ist (Ich buddel ihn auch nict aus).
Grüße von der wolkigen Nordsee
Peter
|
|
Th69
Beiträge: 4791
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Di 06.07.21 11:32
Weißt du denn (nicht), was die Parameter der AddNew-Methode bedeuten?
Dies sind beides Arrays, in denen du die Spaltennamen und Spaltenwerte einträgst (mindestens also die "required"-Felder).
Hier ein Beispiel:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| var oleFieldNames:OleVariant; oleFieldValues:OleVariant; begin oleFieldNames := VarArrayOf(['Id','Name','Number']); oleFieldValues := VarArrayOf([Id, 'Test', 42]);
ADORecordSet.AddNew(oleFieldNames,oleFieldValues); end; |
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Di 06.07.21 16:41
Hallo Th69,
Dank Dir für Deine konstruktive Antwort.
Ich habe mich nicht sehr intensiv mit der ADO beschäftigt, wie gesagt, ich habe "ADO DataSet component" im Internet gefunden und verwendet.
Das Problem dabei ist: Die benötigten Daten werden mit dem Parameter nicht geliefert, sonst wäre das Problem schon gelöst.
Grüße von der jetzt sonnigen Nordsee
Peter
|
|
Sinspin
Beiträge: 1334
Erhaltene Danke: 118
Win 10
RIO, CE, Lazarus
|
Verfasst: Di 06.07.21 17:23
Peter18 hat folgendes geschrieben : | Hallo Sinspin,
auch eine ganz tolle Antwort!!!!!!!!!!!!!! |
Perfekt! Gern geschehen .
Warum verwendest Du nicht TADOTable anstelle von TADODataSet?
Laut emba Hilfe kann die genau das was du brauchst.
TADODataSet stellt, laut der gleichen emba Hilfe nur die Basisfunktionalität bereit die alle abgeleiteten Komponenten gemeinsam haben. Das muss nicht heißen dass dort auch alles so implementiert ist das man damit in einer Tabelle rumwurschteln kann.
€:
Übrigens schießt Du dir mit deiner abweisenden Haltung gegenüber neueren Delphi Versionen nicht nur in ein Knie, sondern in beide, und auch noch in nahezu alle anderen Körperteile.
Du kannst auch nicht erwarten dass sich jemand für dich über Komponenten kundig macht die auf einem mehr als 20 Jahre alten Delphi laufen.
_________________ Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Fr 10.09.21 10:25
Ein freundliches Hallo an alle,
endlich komme ich wieder dazu mich mit meiner Software zu befassen.
Hallo Th69,
nochmals Dank für Deine Antwort! Offenbar ist "AddNew" in db.pas (deren Quelle ich nicht habe) virtuell deklariert, aber nicht in "ADORecordSet" Nachdem ich das nachgeholt habe, lande ich in der Routine und habe die Daten zur Verfügung. Nun aber gibt es Beschwerden über den Datentyp. Ich trage die Daten als String in das Array ein.
Leider habe ich bisher keine Funktion gefunden, die Auskunft über den Datentyp gibt, oder eine Möglichkeit einen neuen Datensatz aus Strings zu erstellen. Vielleicht hast Du einen Tip.
Hallo Sinspin,
Sinspin hat folgendes geschrieben : | Warum verwendest Du nicht TADOTable anstelle von TADODataSet?
Laut emba Hilfe kann die genau das was du brauchst. |
Hab ich nicht!
Sinspin hat folgendes geschrieben : | Übrigens schießt Du dir mit deiner abweisenden Haltung gegenüber neueren Delphi Versionen nicht nur in ein Knie, sondern in beide, und auch noch in nahezu alle anderen Körperteile.
Du kannst auch nicht erwarten dass sich jemand für dich über Komponenten kundig macht die auf einem mehr als 20 Jahre alten Delphi laufen. |
Es gibt gute Gründe warum ich diesen Compiler verwende! Ich habe nicht die Absicht diese Gründe hier zu diskutieren!
Es geht nicht um den Compiler sondern um die Schnittstelle! Es soll ja Leute geben, die sich damit auskennen.
Grüße von der wolkigen Nordsee
Peter
|
|
jasocul
Beiträge: 6388
Erhaltene Danke: 146
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Mo 13.09.21 08:40
Peter18 hat folgendes geschrieben : | Nun aber gibt es Beschwerden über den Datentyp. Ich trage die Daten als String in das Array ein.
Leider habe ich bisher keine Funktion gefunden, die Auskunft über den Datentyp gibt, oder eine Möglichkeit einen neuen Datensatz aus Strings zu erstellen. Vielleicht hast Du einen Tip. |
AdoRecordset sollte eine Eigenschaft Fields haben. Das ist ein Array über alle Felder eines Datensatzes. Dort sollte dann eine Eigenschaft FieldType existieren, die den Feldtyp liefert. Du könntest natürlich auch einfach auf der Datenbank nachsehen, welcher Typ verlangt ist, falls du die Möglichkeit dazu hast.
Du trägst bei dir alle Informationen als String ein. Das führt offensichtlich zu einem Fehler. Ich gehe davon aus, dass Th69 deswegen ein VarArray in seinem Beispiel vorgeschlagen hat. Dann bist du nicht auf String beschränkt und kannst jedem Feld die Daten im gewünschten Typ anliefern.
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Mo 13.09.21 12:12
Hallo jasocul,
Dank Dir für die Antwort.
Ich habe auch schon in dieser Richtung geforscht, aber noch nichts gefunden, dass eine Richtung vorgibt. Diverse Auflistungen von Eigenschaften und Methoden, aber nichts bisher, dass mir einen Weg weist. Leider komme ich heute nicht mehr dazu mir die Fields Eigenschaft anzusehen.
Meine Idee ist, den Datensatz durch zu arbeiten, die Daten in den geforderten Datentyp umzuwandeln und der Routine zu übergeben. Vielleicht hast Du ja noch einen Tipp in dieser Richtung??
Grüße von der wolkigen Nordsee
Peter
|
|
jasocul
Beiträge: 6388
Erhaltene Danke: 146
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Mo 13.09.21 12:32
Hallo Peter,
also die Eigenschaft lautet ADODataSet.Fields[<Feld-Index>].DataType
Mögliche Ergebnisse sind:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| ftUnknown, ftString, ftSmallint, ftInteger, ftWord, ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime, ftBytes, ftVarBytes, ftAutoInc, ftBlob, ftMemo, ftGraphic, ftFmtMemo, ftParadoxOle, ftDBaseOle, ftTypedBinary, ftCursor, ftFixedChar, ftWideString, ftLargeint, ftADT, ftArray, ftReference, ftDataSet, ftOraBlob, ftOraClob, ftVariant, ftInterface, ftIDispatch, ftGuid, ftTimeStamp, ftFMTBcd, ftFixedWideChar, ftWideMemo, ftOraTimeStamp, ftOraInterval, ftLongWord, ftShortint, ftByte, ftExtended, ftConnection, ftParams, ftStream, ftTimeStampOffset, ftObject, ftSingle |
In D4 kann das abweichen.
Du hast ja im Moment den Weg eingeschlagen, den Datensatz über ein VarArray einzutragen.
Allerdings geht auch sowas: ADODataSet.Fields[<Feld-Index>].AsVariant = <alles möglich. Typ ist egal>
Das ist aber nicht besonders schnell. Schneller geht es, wenn du den richtigen Typ nimmst. Dann ist z.B. ADODataSet.Fields[<Feld-Index>].AsString = 'irgendein String'
Über Performance muss du dir aber nur Gedanken machen, wenn du größere Datenmengen verarbeiten willst.
Ansonsten führen viele Wege nach Rom. Ich würde das vermutlich in einer Klasse kapseln. Du könntest aber einfach eine Schleife um die Fields-Eigenschaft bauen und über ein case auf den FieldType das Array aufbauen.
Moderiert von Th69: Delphi-Tags hinzugefügt
|
|
|