Entwickler-Ecke

Datenbanken - ADO: Leeren Datensatz erzeugen


Peter18 - So 27.06.21 12:28
Titel: ADO: Leeren Datensatz erzeugen
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


Th69 - So 27.06.21 12: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 [http://docwiki.embarcadero.com/Libraries/Rio/de/Vcl.DBGrids.TDBGrid]?


Peter18 - So 27.06.21 13: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 - So 27.06.21 13: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 - So 27.06.21 13: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 - So 27.06.21 15: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 - Mo 28.06.21 11: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 - Mo 28.06.21 11: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 :gruebel: ).


Peter18 - Mo 28.06.21 12: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 - Mo 28.06.21 15:36

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
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.


jaenicke - Mo 28.06.21 17: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...

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
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.

user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
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 - Di 29.06.21 12: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 - Di 06.07.21 11: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 - Di 06.07.21 12:32

Weißt du denn (nicht), was die Parameter der AddNew [https://docs.microsoft.com/de-de/sql/ado/reference/ado-api/addnew-method-ado]-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 - Di 06.07.21 17: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 - Di 06.07.21 18:23

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
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.


Peter18 - Fr 10.09.21 11: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,

user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Warum verwendest Du nicht TADOTable anstelle von TADODataSet?
Laut emba Hilfe kann die genau das was du brauchst.

Hab ich nicht!

user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Ü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 - Mo 13.09.21 09:40

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
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 - Mo 13.09.21 13: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 - Mo 13.09.21 13: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 user profile iconTh69: Delphi-Tags hinzugefügt


Peter18 - Mo 13.09.21 17:12

Hallo Peter,

Nochmals Dank!!!

Mein Problem ist ein neuer Datensatz! Daher dieser Weg. Vielleicht gibt es ja noch einen??? "ADODataSet.Fields[<Feld-Index>].AsString" wäre schön!! Aber wenn ich einen leeren Datensatz erzeuge, gibt es Gemecker wegen "required". Wenn es da einen Weg gibt wäre ich begeistert!!

Grüße von der jetzt sonnigen Nordsee

Peter

Moderiert von user profile iconTh69: Delphi-Tags hinzugefügt


jasocul - Di 14.09.21 07:34

Vielleicht haber ich die ganze Zeit zu kompliziert gedacht.
Warum willst du einen leeren Datensatz erzeugen, um dann die Felder zu füllen?

Versetze die Tabelle in den Erfassen-Zustand:

Delphi-Quelltext
1:
ADODataSet.Append;                    

Dadurch ist der Datensatz noch nicht gespeichert (die DB hat dann nichts zu meckern), aber für die Feldzuweisungen verfügbar:

Delphi-Quelltext
1:
2:
ADODataSet.Fields[<Feld-Index>].AsString := 'Hallo Welt';
ADODataSet.Fields[<anderer Feld-Index>].AsInteger := 4711;

Wenn alle Zuweisungen gemacht wurden, kommt noch:

Delphi-Quelltext
1:
ADODataSet.Post;                    

Oder gibt es einen speziellen Grund, warum der Datensatz bereits existieren muss?


jaenicke - Di 14.09.21 08:49

Das ist halt schwierig, wenn man ein einfaches Grid verwendet, bei dem der Benutzer aus der Zeile herauskommt ohne alles zu füllen wie bei einem DB-Grid.

Deshalb hatte ich ja im Juni geschrieben:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
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...


Es gibt nun einmal nicht viele Möglichkeiten, wenn man an einer bestimmten Eingabeweise und dann noch an einer uralten Delphiversion hängt. Ohne Kompromisse geht es dann eben nicht. :nixweiss:


jasocul - Di 14.09.21 10:24

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Das ist halt schwierig, wenn man ein einfaches Grid verwendet, bei dem der Benutzer aus der Zeile herauskommt ohne alles zu füllen wie bei einem DB-Grid.

Das ist schon richtig. Allerdings muss user profile iconPeter18 ja irgendeinen Auslöser kennen, der ihn zum Speichern veranlasst. An der Stelle müssen dann das Append und die Zuweisungen, sowie der Post erfolgen.


Peter18 - Mi 15.09.21 16:51

Hallo Peter,

nochmals Dank!!!

Genau da war ich schon einmal. Dann ist jedoch ein Fehler in "unit ADODataSet;" aufgetreten. Die "unit ADODataSet;" habe ich im Internet gefunden und sie enthält offenbar einen Fehler.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TADODataSet.InternalInitRecord(Buffer: PChar);
begin
  DoMessage('InternalInitRecord');
  FillChar(Buffer^, GetRecordSize, 0);
  try
    ADORecordSet.AddNew(0, null);
  except
    ADORecordSet.AddNew( ADORecordSet.Fields, EmptyParam );       
  end;
  //ADORecordSet.Update(EmptyParam, EmptyParam);
  PadoInfo(Buffer+StartInfo).BookmarkInt:=ADORecordSet.Bookmark;
//  NewRec:=PadoInfo(Buffer+StartInfo).BookmarkInt;
  EMode:=False;
end;

"ADORecordSet.AddNew(0, null);" hat ein Problem mit "required".

"TADODataSet.Append" existiert nicht. Daher lande ich anscheinend in "InternalInitRecord".

Es muß doch auch in ADO die Möglichkeit geben einen Leeren Datensatz zum Bearbeiten zu erzeugen!

Auch Lazarus hat mich bisher nicht weiter gebracht. Vielleicht muß ich da mal ein Testprogramm schreiben.


Hallo jaenicke,

Wie schon erwähnt: Es gibt gute Gründe warum ich diesen Compiler verwende! Ich habe nicht die Absicht diese Gründe hier zu diskutieren!

Grüße von der regnerischen Nordsee

Peter


jaenicke - Mi 15.09.21 20:01

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
"TADODataSet.Append" existiert nicht. Daher lande ich anscheinend in "InternalInitRecord".
Append existiert in jeder von TDataSet abgeleiteten Klasse, so auch in TADODataSet.

Und ein Blick in den Quelltext von Delphi 4 (Source\Vcl\db.pas, Zeile 8329) zeigt, dass dort in TDataSet.Append InitRecord (und darin InternalInitRecord) aufgerufen wird.

Bei mir funktioniert das TADODataSet.Append auch problemlos in Delphi 5 (mit den mitgelieferten Demo-Datenbanken). Delphi 4 kann ich leider nicht testen, da ich davon nur die Professional Edition habe, die keine ADO Komponenten hatte.

Vielleicht liegt das Problem auch am verwendeten OLE DB Provider oder dem verwendeten Datenbanksystem (was hier beides nicht bekannt ist). Damit gab es damals immer viel Spaß...


jasocul - Do 16.09.21 07:16

Mir geht es ähnlich wie user profile iconjaenicke. Irgendwo habe ich noch D5 und vielleicht sogar D3, aber D4 leider nicht. Ich kann das daher an dieser Stelle auch nicht weiter prüfen. Sorry.


jaenicke - Do 16.09.21 08:33

Ich vermute allerdings, dass der Unterschied zwischen Delphi 4 und 5 nicht so groß ist. Ich vermute eher, dass sich die integrierten Demos durch die einfachen Datentypen (und vermutlich einem anderen Datenbanksystem) pflegeleichter verhalten.

Um dazu etwas zu sagen, fehlen aber die entsprechenden Informationen zum Datenbanksystem, dem verwendeten Provider für die Connection (im Zweifelsfall der Connection String) sowie zur Struktur der Tabelle und der Abfrage, um die es geht.

user profile iconjasocul hat folgendes geschrieben Zum zitierten Posting springen:
Irgendwo habe ich noch D5 und vielleicht sogar D3
Ich habe mal, als es bei Ebay noch solche Angebote gab, ein paar Versionen ersteigert. Deshalb habe ich hier eine VM mit Windows XP, in der unter anderem von Delphi 1 bis 7 alles da ist, nur eben teilweise nur als Professional.


Th69 - Do 16.09.21 12:06

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Die "unit ADODataSet;" habe ich im Internet gefunden und sie enthält offenbar einen Fehler.

Könntest du mal den Link dazu hier posten?


jaenicke - Do 16.09.21 12:10

Das hatte ich glatt überlesen. Ich war von dem mitgelieferten TADODataSet ausgegangen...


Th69 - Do 16.09.21 12:18

Die "ADO Express"-Komponenten gibt es (wohl) erst seit Delphi 5 [https://de.wikipedia.org/wiki/Embarcadero_Delphi#Delphi_5_(Codename:_Argus)].


Peter18 - Do 16.09.21 12:21

Hallo jaenicke, hallo Peter,

Dank Euch für die Antworten!!

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Und ein Blick in den Quelltext von Delphi 4 (Source\Vcl\db.pas, Zeile 8329) zeigt, dass dort in TDataSet.Append InitRecord (und darin InternalInitRecord) aufgerufen wird.

Das ist ja gerade mein Problem! Diese Quelldatei fehlt mir!

Ich glaube zwar nicht, dass es weiter hilft: "Provider=Microsoft.Jet.OLEDB.4.0" Die Testdatenbank ist "Nordwind.mdb" Tabelle: "Kunden".

Wenn aber "InternalInitRecord" dort aufgerufen wird, so muß der Fehler dort liegen. Dort wird "ADORecordSet.AddNew" aufgerufen und ein leerer Datensatz erstellt. Das führt zum Konflikt mit "required". Es sollte doch möglich sein einen leeren Datensatz zum editieren bereit zu stellen.


Delphi-Quelltext
1:
2:
oDatSet.Edit;
oDatSet.Append;
Hilft nicht.

Vielleicht hilft eine der Routinen: AppendRecord, DisableControls, InsertRecord oder eine Eigenschaft muß umgeschaltet werden?

Hallo Th69,

diese Unit habe ich nicht wieder gefunden, vielleicht ist sie nicht mehr im Internet. Im Kopf der Datei steht:
Zitat:
// ADO DataSet component v0.9
// Written by Larry Nezar (LarryN@nda.agric.za)
// Date of last modification: 28/7/1999


Grüße von der regnerischen Nordsee

Peter


jaenicke - Do 16.09.21 12:43

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Das ist ja gerade mein Problem! Diese Quelldatei fehlt mir!
Dann hast du vermutlich das Häkchen für die Quelltexte, das es damals noch im Setup gab, nicht gesetzt. Von Delphi 4 gab es meines Wissens keine Version ohne die Quelltexte.

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Ich glaube zwar nicht, dass es weiter hilft: "Provider=Microsoft.Jet.OLEDB.4.0" Die Testdatenbank ist "Nordwind.mdb" Tabelle: "Kunden".
Access und Jet 4.0 Provider mit ADO... eigentlich habe ich da schon keine Lust mehr... ;-)

Wie wäre es, wenn du einfach eine DLL in einer aktuellen Delphiversion erstellst, die die Access-Datenbank anspricht, und diese in deine Software in Delphi 4 einbindest? Damit würdest du viel Zeit sparen und könntest die Software selbst weiter in Delphi 4 entwickeln.

Ansonsten bräuchte ich noch die Tabellenstruktur (ohne Daten) um das mit Delphi 5 mal zu testen.


Th69 - Do 16.09.21 13:02

@Peter18: Dann hänge doch mal diese Datei hier an (damit wir mal da reinschauen können).

Da das Feld "KundenCode" in der "Kunden"-Tabelle erforderlich ist (s. z.B. ER-Diagramm der Nordwind-Datenbank [https://luo-darmstadt.de/sqltutorial/db_nordwind.html]), mußt du dieses eben (wie von mir schon weiter oben als Code gezeigt) bei AddNew als Parameter hinzufügen!


Peter18 - Do 16.09.21 14:52

Hallo,

hier die Datei ADODataSet. Es sind etliche Zeilen durch den Autor auskommentiert. Einige von mir, weil sie beim ersten compilieren zu Fehlern führten und für die benötigten Funktionen zunächst nicht nötig waren. Diese Zeilen muß ich noch heraussuchen. (Dauert etwas) Diese Datei ist das Original des Autors.

Daten einlesen und ändern geht wunderbar, nur neuer Datensatz nicht.

Dieses Programm will ich auf verschiedene Datenbanken loslassen, sonst könnte ich die Datentypen hart verdrahten.

Grüße von der Nordsee

Peter


Th69 - Do 16.09.21 16:00

Bist du sicher, daß das der Original-Code ist?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure TADODataSet.InternalAddRecord(Buffer: Pointer; Append: Boolean);
begin
  DoMessage('Add new record...');
//  ADORecordSet.Bookmark:=PadoInfo(PChar(Buffer)+StartInfo).BookMarkInt;
//  ADORecordSet.AddNew(EmptyParam, EmptyParam);
//  PadoInfo(Buffer+StartInfo).BookMarkInt:=ADORecordSet.Bookmark;
  EMode:=True;
end;

procedure TADODataSet.InternalInitRecord(Buffer: PChar);
begin
  DoMessage('InternalInitRecord');
  FillChar(Buffer^, GetRecordSize, 0);
  ADORecordSet.AddNew(0, null);
  ADORecordSet.Update(EmptyParam, EmptyParam);
  PadoInfo(Buffer+StartInfo).BookmarkInt:=ADORecordSet.Bookmark;
//  NewRec:=PadoInfo(Buffer+StartInfo).BookmarkInt;
  EMode:=False;
end;

Du hattest oben doch anderen Code gepostet...

Funktioniert es denn einwandfrei bei Tabellen ohne "required"-Felder?


Peter18 - Do 16.09.21 16:41

Th69Hallo Th69,

selbstschmunzeln ist das das Original! Das von oben enthält meine Experimente.

Die übrigen Änderungen habe ich zurückgenommen, ohne ein anderes Verhalten zu erreichen.

Grüße von der Nordsee

Peter


jaenicke - Do 16.09.21 17:23

Kannst du die Datenbankdatei vielleicht auch noch anhängen bitte? Daten brauche ich nicht darin.


Peter18 - Do 16.09.21 17:43

Hallo an alle,

ich habe einen Verdacht!

Ich habe die Werte mit AsString ausgelesen. Es wird ein Feld "Kunden.Firma" angemeckert. Ein solches Feld sehe ich in meiner Tabelle und in der Datenbank nicht. In der Datenbank sind Verweise auf andere Tabellen enthalten. Ich vermute diese Verweise verursachen das Problem. Doch wie Erkenne ich sie und wie komme ich an das Feld? Oder die Information zu dem Schlüssel?

In der Entwurfsansicht bei Access erscheint nur ein Schlüssel, kein Feldname.

Auf besonderen Wunsch die Datenbank (hoffentlich alles nötige. (Vielleicht kannst Du mir ja auch die db.pas zukommen lassen))

Grüße von der Nordsee

Peter


jaenicke - Do 16.09.21 20:30

Ich habe leider keinen Zugriff mehr auf so alte Access Versionen. Das .adp Format ist seit mehr als 10 Jahren nicht mehr in Access verwendbar...
Wenn ich die Datei versuche mit einem aktuellen Access Provider zu öffnen, geht da auch nichts.

Ich kann die Datei aber auch unter XP nicht mit dem Jet 4.0 Provider verwenden. Das Format wird da nicht erkannt, da gehen nur .mdb Dateien.

Keine Ahnung, das ist alles zu lange her als dass ich davon Ahnung hätte. Damals war ich noch in der Schule und habe mich mit solchen Dingen noch nicht beschäftigt...

Die db.pas wird dir ohne den Rest nicht viel helfen, denn ohne die nötigen Debug-DCUs usw. kannst du darin nicht debuggen. Insofern bliebe nur das entsprechend zu installieren (VCL Source ist der entscheidende Punkt):

D4