Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   PDF in Blob speichern mit seltsamen Effekten (https://www.delphipraxis.net/177939-pdf-blob-speichern-mit-seltsamen-effekten.html)

Jumpy 6. Dez 2013 16:01

Datenbank: Oracle • Version: 11g • Zugriff über: Ado

PDF in Blob speichern mit seltsamen Effekten
 
Hallo,

ich habe eine DB-Anwendung, bei der zu bestimmten Datensätzen je 1 Dokument als PDF in der DB gespeichert wird. Dazu gibt es eine Extra-Tabelle die nur aus ID und Blobfeld besteht. Die ID ist jeweils die selbe wie die des zugehörigen Datensatzes, d.h. PK und FK in Personalunion.

Ich lade die Datei in einen Stream und diesen dann als Blobstream in die DB. Dabei halte ich mich an eine Anleitung, die ich hier in einem Thread mal gelesen habe, aber gerade nicht finde (ich meine das wäre von Perlsau gewesen).

Klappt soweit alles prima.

Problem: Es kommt gelegentlich vor, das die PDF-Datei des Datensatzes ersetzt werden muss. Da hab ich dann zuerst einfach den Stream wieder in das Blobfeld geschrieben. Das hat aber nicht geklappt (keine Fehlermeldung oder so, sondern es war einfach nur immer noch die alte Datei drin). Dann habe ich stattdessen den Datensatz in der Tabelle einfach gelöscht und einen neuen angelegt mit der alten ID und einem leeren Blobfeld, in das ich dann wieder die Datei gestreamt habe. Das klappt jetzt manchmal. Und manchmal halt nicht, dann ist da irgendeine andere Datei drin (z.B. eine die ein paar Minuten vorher angepackt wurde) und die zu einem anderen Datensatz gehörte.

Das passiert aber nicht nur bei einer Desktopanwendung, auch bei einer Web-CGI. D.h. es kann mMn nichts mit nicht freigegebenen Dingen in Delphi zu tun haben oder so, da die CGI sich ja nach jeder Aktion beendet.

Es muss also irgendwie mit der DB zusammenhängen und meiner unerfahrenheit mit Blobs. Ist das vllt. irgendwie träge? Wie räumt Oracle da auf?

Perlsau 6. Dez 2013 16:26

AW: PDF in Blob speichern mit seltsamen Effekten
 
Ich denke, du meinst diese beiden Proceduren. Leider ist es nicht möglich, anhand deiner umfangreichen Beschreibung festzustellen, was genau du falsch gemacht hast. Mit anderen Worten: Es wäre hilfreich, wenn man als hilfsbereiter Mensch auch sehen könnte, was du geschrieben hast, um ein existierendes Blobfeld zu überschreiben. Meinen beiden Methoden ist es völlig egal, ob es sich dabei um ein gerade erst erstelltes oder ein bereits bestehendes leeres oder gefülltes Blobfeld handelt. Wichtig ist nur, daß erstens die Tabelle in den Editier- bzw. Appendmodus versetzt wird, bevor man die Procedure File_To_Blob aufruft, und zweitens nach dem Einlesen ins Blobfeld wieder mit Post geschlossen wird. Wird das Post vergessen, bleiben die Änderungen wirkungslos und der bestehende Blob-Inhalt wird nicht überschrieben.

Bernhard Geyer 6. Dez 2013 16:38

AW: PDF in Blob speichern mit seltsamen Effekten
 
Bei Oracle und Ado muss man eigentlich fragen welcher Provider verwendet wird. Die von MS haben bekanntlich ja so ihre Fehler.

p80286 6. Dez 2013 17:42

AW: PDF in Blob speichern mit seltsamen Effekten
 
Nicht nur, die Oracles sind auch manchmal Zickig, und es kommt auf die genaue Version an!

Wenn Du keine vernünftige Doku hast, hilft wohl nur ausprobieren.
Ohne Gewähr: (mir ist bekannt, daß der Oracle Provider keine Memos mag. u.u mußt Du noch ODBC dazwischen packen, da war mal was, die Details sind mir aber entschwunden.

Gruß
K-H

Jumpy 9. Dez 2013 09:32

AW: PDF in Blob speichern mit seltsamen Effekten
 
Hallo,

der Zugriff erfolgt mit den ADO-Komponenten, die bei Delphi (diesmal D2010) dabei sind. Es ist aber noch Oracles ODBC dazwischen, d.h. ADO->ODBC->Oracle.

Hier mal die Funktion wie ich sie jetzt benutze, wo ich nur noch evtl. schon vorhandene Einträge lösche (die Funktion ist jetzt nicht hier dabei, da einfach nur ein Delete) und dann neu einfüge.
Vorher stand da anstatt q.Insert sowas ala "If IDExists(ID) then q.Edit else q.Insert;"

Delphi-Quellcode:
procedure TBL.PutFileInDB(const id,Typ,fname:String; var filesize:integer);
var q:TADOTable;
    s:TStream;
    f:TFileStream;
begin
  q:=TADOTable.Create(nil);
  q.Connection:=Con;
  q.TableName:=Table(TabDatei);
  q.Open;
  If FileExists(fname) then
    begin
    q.Insert;
    q.FieldByName('ID').AsString:=id;
    q.FieldByName('Typ').AsString:=Typ;
    s:=q.CreateBlobStream(q.FieldByName('Datei'), bmReadWrite);
    f:=TFileStream.Create(fname, fmOpenRead);
    filesize:=s.CopyFrom(f,f.Size);
    f.Free;
    s.Free;
    q.Post;
    end
  else
    filesize:=0;
  q.Free;
end;
@Perlsau: Was du gezeigt hast, war in etwa was ich meinte, aber das war in einem anderen Thread, wo du das noch ausführlicher geschrieben hast, ich kanns aber wie gesagt nicht mehr finden, war auch schon älter. Ich hab deine Funktion dabei nur als Hinweis genommen, wie man in den Blob schreibt/streamt, das aber nicht als eigene Funktion abstrahiert, sondern einfach mit dem Füllen der restlichen Tabellenfelder in einer Funktion gelassen.

Was mir aufgefallen ist, ist, das du in deinem Post von "Append" gesprochen hast, ich aber "Insert" benutzt habe. Könnte das Probleme im Zusammenhang mit Blobs Probleme machen? Der unterschied ist wie ich das verstanden habe ist doch nur, ob sich der Datensatzzeiger vor dem Einfügen ans Ende verschiebt oder nicht und ich dachte, das betrifft nur die clientseitige Anzeige und nicht den Speicherort in der DB oder so.

jobo 9. Dez 2013 10:28

AW: PDF in Blob speichern mit seltsamen Effekten
 
Du hast noch nicht geschrieben, ob Du Oracle oder MS Oracle Treiber verwendest. Bei BLOB habe ich sehr schlechte Erfahrung mit dem alten MS Treiber gemacht.
Ansonsten musst Du in Deinem Code vielleicht auch den Stream an das Feld schicken.

P.S.: Warum du gleich eine ganze Table für das Update aufmachst, ist mir auch nicht so klar. Gerade bei BLOB Spalten kann das sehr viel kosten.
Insgesamt sieht Dein Code außerdem nicht nach Update, sondern nur Insert aus.

Perlsau 9. Dez 2013 10:50

AW: PDF in Blob speichern mit seltsamen Effekten
 
Hi Jumpy,

meine Funktion hatte ich so gestaltet, daß sie für alle Eventualitäten brauchbar ist. Prüfungen auf z.B. existierende Datei oder Datensatz erfolgen von der aufrufenden Methode. Das kannst du dir natürlich so hinbasteln, wie du es benötigst.

Der Unterschied zwischen Append und Insert besteht darin, daß bei Append ein Datensatz physikalisch am Ende der Tabelle eingefügt wird, bei Insert jedoch an der physikalischen Stelle des Datensatz-Zeigers (ob darüber oder darunter weiß ich nicht). Für die genannte Funktion spielt das jedoch kenie Rolle.

Offenbar hast du es nun geschafft, eine Binärdatei (denn nichts anderes ist ein PDF-Dokument) in einem Blobfeld zu speichern. Deinen Code hab ich mir jetzt aber nicht angeschaut.

Jumpy 9. Dez 2013 13:22

AW: PDF in Blob speichern mit seltsamen Effekten
 
@Jobo:
Der Code sieht nach Insert aus, weil ich nur noch Inserts mache, nachdem die Updates/Edits nicht geklappt haben. Ursprünglich sah der Code leicht anders aus (siehe Beschreibung davor).

Ich benutze die Oracle-ODBC-Treiber, da (wie ja auch von dir) von den MS-Treibern immer abgeraten wird und diese afaik ja auch nicht mehr gepflegt werden.

Warum ich mir die ganze Tabelle "rüberhole" um einen DS darin zu speichern, hab ich mir ehrlich gesagt noch keine Gedanken drüber gemacht. Das war halt in dem Beispiel so und ich dachte das passt.
Zuvor hab ich das mit einem SQL-Insert-Statement versucht, aber das hab ich gar nicht hinbekommen und auch kein gutes Beispiel gefunden, weswegen ich auf die obige Variante umgeschwenkt bin.
Ich muss mal versuchen, das mit einer TQuery umzusetzten. Vielleicht klappt das ja auch.

@Perlsau
Zitat:

Der Unterschied zwischen Append und Insert besteht darin, daß bei Append ein Datensatz physikalisch am Ende der Tabelle eingefügt wird, bei Insert jedoch an der physikalischen Stelle des Datensatz-Zeigers (ob darüber oder darunter weiß ich nicht). Für die genannte Funktion spielt das jedoch kenie Rolle.
Vielleicht spielt es ja im Falle von Oracle Blobs doch eine Rolle? Sicherheitshalber versuch ich es auch einfach mal mit Append.

chuckholdt 9. Dez 2013 15:49

AW: PDF in Blob speichern mit seltsamen Effekten
 
Bin nicht ganz sicher, wie die Felder arbeiten, aber du gibts den Stream vor dem POST frei, das könnte zu komischen Effekten führen.

Chuck

Perlsau 9. Dez 2013 16:48

AW: PDF in Blob speichern mit seltsamen Effekten
 
Zitat:

Zitat von Jumpy (Beitrag 1239117)
@Perlsau
Zitat:

Der Unterschied zwischen Append und Insert besteht darin, daß bei Append ein Datensatz physikalisch am Ende der Tabelle eingefügt wird, bei Insert jedoch an der physikalischen Stelle des Datensatz-Zeigers (ob darüber oder darunter weiß ich nicht). Für die genannte Funktion spielt das jedoch kenie Rolle.
Vielleicht spielt es ja im Falle von Oracle Blobs doch eine Rolle? Sicherheitshalber versuch ich es auch einfach mal mit Append.

Mit Sicherheit werde ich das nicht versuchen. Weißt du auch warum nicht? Ganz einfach: Ich habe gar kein Oracle :stupid:

DeddyH 9. Dez 2013 16:51

AW: PDF in Blob speichern mit seltsamen Effekten
 
Zitat:

Sicherheitshalber versuch ich es auch einfach mal mit Append.
:stupid:

Perlsau 9. Dez 2013 16:57

AW: PDF in Blob speichern mit seltsamen Effekten
 
Zitat:

Zitat von chuckholdt (Beitrag 1239148)
Bin nicht ganz sicher, wie die Felder arbeiten, aber du gibts den Stream vor dem POST frei, das könnte zu komischen Effekten führen.

Was sind denn "komische Effekte"? Davon hab ich noch nie was bemerkt! Wieso sollte es den Eintrag in der Datenbank jucken, wenn der Stream, der ihn geliefert hatte, abkratzt? Genau so gut könntest du in einer lokalen Procedure Zuweisungen an DB-Felder machen und in einer anderen Procedure dann erst mit Post abschließen:
Delphi-Quellcode:
Procedure Zuweisen;
Var
  Feld1 : Integer;
  Feld2 : String;
  Feld3 : Boolean;
Begin
  Feld1 := Self.Tag;
  Feld2 := Application.ExeName;
  Feld3 := Self.WindowState = wsMaximized;
  MyDataSet.FieldByName('Field1').AsInteger := Feld1;
  MyDataSet.FieldByName('Field2').AsString := Feld2;
  MyDataSet.FieldByName('Field3').AsBoolean := Feld3;
End;

Procedure NeuerEintrag;
Begin
  MyDataSet.Append;
  Zuweisen;
  MyDataSet.Post;
End;
Was meinst du: würde das funktionieren oder ergäbe das eine Fehlermeldung?

jobo 10. Dez 2013 06:35

AW: PDF in Blob speichern mit seltsamen Effekten
 
Ich hab mal diese Variante von swissdelphicenter probiert:
http://www.swissdelphicenter.ch/torr...de.php?id=1271

Funktioniert mit Oracle OLEDB und MS OLEDB über Oracle ODBC unter Delphi 5. Hab allerdings ein paar Bilder zum Test genommen und der Code musste bei der Blob Variable auf Typ TStream umgestellt werden.

Das läuft sowohl bei einer AdoQuery innerhalb eines Inserts oder als Update eines bestehenden Records.

Jumpy 10. Dez 2013 08:57

AW: PDF in Blob speichern mit seltsamen Effekten
 
Zitat:

Zitat von DeddyH (Beitrag 1239160)
Zitat:

Sicherheitshalber versuch ich es auch einfach mal mit Append.
:stupid:

Ich weiß ja, Yoda sagt es gibt kein "Versuchen". Man muss es einfach nur tun.
Das zeigt halt, dass ich schon bereit bin mich an Strohhalme zu klammern, weil ich nicht verstehe, wie das Problem zustande kommt.

Wie gesagt ich kriegt ja die Files in die DB geschrieben und ich krieg sie ja wieder ausgelesen, das Vorgehen funktioniert ja prinzipiel. Nur kommt halt manchmal die falsche Datei beim wieder auslesen raus. Und bevor jetzt einer Meckert: Ich hab das im Debugger durchgespielt, ich hab das direkt and er SQL-Console durchgespielt, es kommt nicht zu ID Verwirrungen, ich fordere genau die Datei an, die ich haben will nur kommt (in den unerklärlichen problemtischen Fällen) nicht die raus, die ich will.

Bzgl. Streams freigeben:
Ich hab per Trial and Error festgestellt, dass man bei meiner Methode die Streams for dem .Post freigeben muss. Es macht aber auch irgendwo Sinn, dass der Stream, nachdem er in den Datensatz geschrieben wurde geschlossen werden muss bevor ich den Datensatz an die DB poste. Soweit ich mich erinnere kam dann keine Fehlermeldung oder so, es war einfach nichts in der DB, bzw. das Feld ID und das Feld Typ waren wohl in der DB angekommen, aber das Blobfeld blieb leer.

Ich baue mir gerade eine Testumgebung, wo ich mal ein paar eurer vorgeschlagenen Varianten durchspielen will. Bei dem Link von Jobo scheint es ja so zu sein, das die Datenmenge gar nicht mit Edit/Insert und Post "behandelt" wird. Muss das nicht, oder ist das wie bei Perlsau so, dass das in der vorgeschalteten Prozedur gemacht wird?
Das blob.Seek sollte doch eigentlich nicht nötig sein, da der Zeiger nach dem Öffnen des Streams doch eh noch am Anfang stehen sollte, oder?

jobo 10. Dez 2013 09:24

AW: PDF in Blob speichern mit seltsamen Effekten
 
Das Dataset.Edit mache ich in meinem Test manuell per Navigator, entweder gar nicht, weil Insert gedrückt oder halt Navigator.Edit gedrückt.
Das blob.seek ist vielleicht ein "Erfahrungswert", der Dir fehlt. :)

Ansonsten bin ich mir nach Deinen Beiträgen nicht sicher, dass Du tatsächlich die richtigen Treiber verwendest.
In meinem Fall jedenfalls Oracle Instant Client mit OLEDB und ODBC.
Für die Connection entweder direkt Oracle OLEDB oder den Umweg über
MS OLEDB ODBC, dort dann Oracle ODBC Treiber des Instant Client.

In meinem Fall ein 11er Treiber, 11.2 auf einer 10.2er DB.

Jumpy 10. Dez 2013 16:34

AW: PDF in Blob speichern mit seltsamen Effekten
 
Ich hab auch einen 11er Client installiert und gehe auf eine 10er DB.
Welchen Treiber meinst du denn, dass ich den falsch habe?

Der OBDC-Treiber ist der von Oracle: Oracle in OraClient11g_home1.

Oder meinst du den Provider aus dem Connection-String der ADO-Komponente?
So wird der ConnectionString zusammengebaut:

Code:
cs:= 'Provider=MSDASQL.1;'+
     'Persist Security Info=True;'+
     'User ID= ' + UID(v) +';'+
     'Data Source= '+DBName(v) +';'+
     'Password=' + PW(v);


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:29 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz