Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Parameter unter Firedac (https://www.delphipraxis.net/188447-parameter-unter-firedac.html)

Delbor 10. Mär 2016 13:27

AW: Parameter unter Firedac
 
Hi zusammen

@Sir Rufo

Zitat:

Nicht wirklich, oder etwa doch?
Diese Datei soll den Ordner, der die Rohdaten der importierten Bilder enthält, kennzeichnen. Der Tip mit dieser Guid stammt übrigens von dir.
Gleichzeitig soll der vergebene GUID in der DB gespeichert werden.

Allerdings ist mir ein Designfehler unterlaufen. Ich habe das Feld für den GUID der Bildtabelle verpasst, aber eigentlich gehört das Ding in die Kategorientabelle - die enthält "Kategorien" (diesen Namen habe ich seinerzeit falsch gewählt), die jedoch eigentlich den Ordnernamen auf der Festplatte entsprechen. Diese Ordner enthalten meist Fotos, die bei einem bestimmten Ereignis entstanden sind, können aber auch solche enthalten, die sich auf mehrere Ereignisse beziehen.

@Himitsu:
Zitat:

Wenn da 4 bei raus kommt, dann ist irgendwas "kaputt".
Kaputt wohl nicht - ich habs wohl einfach falsch gemacht...
Delphi-Quellcode:
Showmessage('Size of UniqueNameUniqueName := ' + IntToStr(SizeOf(UniqueName)));
Da ich die Bytes wissen wollte, habe ich Size verwendet. Wobei mir das Leerzeichen nach Size erst jetzt auffällt...

Gruss
Delbor

PS: Dacht ichs doch: Wenn ich SizeOf durch Length ersetze, siehts ganzanders us:
[Window Title]
Zitat:

Contentmasterdxe8

[Content]
Size of UniqueName := 38
[OK]

Delbor 10. Mär 2016 14:08

AW: Parameter unter Firedac
 
Hi zusammen
Im Moment siehts ganz danach aus, als ob die DB den String/Stream akzeptiert:
Delphi-Quellcode:
procedure TOpenFileFrame.Btn_OkClick(Sender: TObject);
  var AUser,APass, Bildpfad, LPath : String;
      FolderID : TStringstream; LIdFolder: String; // <=Da Fettdarstellung innerhalb der Delphi-Tags nicht funktioniert -  die Änderungen
      LPathCount, i: integer;  
begin
  LPathCount := Self.FPathlist.Count;
  CM_First.CreateProgressbarDlg(LPathCount);     // Create den ProgressbarDialog und zeigt ihn an // Dazu braucht das System etwas Zeit
  try
    CM_First.ProgressbarDlg.Top := 20;
    CM_First.ProgressbarDlg.Left := (CM_First.ProgressbarDlg.Monitor.Width - CM_First.ProgressbarDlg.Width) div 2;
    Application.ProcessMessages;
    FDMySQLDml.Pathlist.AddStrings(FPathlist);
    CM_First.Listbox1.Items.AddStrings(FPathlist);
    Bildpfad := FPathList[0];
    LPath := ExtractFilePath(Bildpfad)+'IdentFile.cgf';
    if not FileExists(LPath+'IdentFile.cgf') then
    begin   // ist in dem Ordner kein IdentifikationsFile
      FolderID := TStringstream.Create;
      LIdFolder := CreateIDFile(LPath);
      FolderID.WriteString(LIdFolder);                                                /// wird eines angelegt
    end;
    if FDMySQLDml.DefineContentmasterConnection then
    begin
      try
        FDMySQLDml.FDConnectionMySql.StartTransaction;
        FDMySQLDml.BildTabelleInsert2(100, FolderID);                     // Startet die Insert-Prozeduren
        FDMySQLDml.FDConnectionMySql.Commit;
      except
        FDMySQLDml.FDConnectionMySql.Rollback;
      end;
    end;
  finally
      CM_First.ProgressbarDlg.FormStyle := fsnormal;
      CM_First.ProgressbarDlg.Close;
      FreeAndNil(CM_First.ProgressbarDlg);
      if assigned(FolderID) then
        FolderID.Free;
  end;
end;
Für einmal die komplette Prozedure, welche die Inserts startet. Die Änderungen sind fett dargestellt.
Delphi-Quellcode:
procedure TFDMySQLDml.BildTabelleInsert2(Seitenlaenge: Integer; FolderID: TStringstream);
  var BMap: TBitmap; BJpeg: TJPEGImage; SQLString,Bildname, Bildpfad: String;
       BildTabelleLastId,IDBild, i,inserted : Integer; LPicture : TPicture;
       LThumbMemory : TMemoryStream;
begin
  LThumbMemory := TMemoryStream.Create;
  LPicture := TPicture.Create;
  BMap := TBitmap.Create;      //Lokal
  BJpeg := TJpegImage.Create;  //Lokal
  BJpeg.CompressionQuality := 100;
  BJpeg.PixelFormat := jf24Bit;
 try
    FTotal := FPathList.Count;
    for i := 0 to FPathList.Count - 1 do
    begin                                
      FRest := FPathList.Count - i;      
      if FDQueryMain.Active then
        FDQueryMain.Active := False;
      Bildname := ExtractFileName(FPathList[i]);      
      Bildpfad := FPathList[i];
      Delete(BildName,Length(BildName)-3,4);          
        LThumbMemory.Clear;                             //<= Beim 2. durchlauf gibts hier eine AV
        if ExtractFileExt(FPathList[i]) = '.NEF' then  
        begin                                          
          LPicture.LoadFromFile(FPathList[i]);
          BMap.Assign(LPicture.Graphic);
          FModifyBitmap.ScaleBitmaps(BMap, Seitenlaenge);
          BJpeg.Assign(BMap);
          BJpeg.SaveToStream(LThumbMemory);
          BildTabelleLastId := BildInsertQuery(LThumbMemory, FolderId);
          FReportList.Add('  '+ IntToStr(i)+'-TPicAdmin.BildTabelleInsert2');
          FReportList.Add(' ');
          BildDescribeTabelleInsert(BildTabelleLastId,BildName,Bildpfad);   //Ab hier werden nacheinander die Insert-Prozeduren
          inserted := 1;                                                    //aufgerufen
          if Assigned(FOnInsertedRecord) then           //<== Hier wird das Event gefeuert; zu dem Zeitpunkt wurde
            FOnInsertedRecord(Self,inserted);         //<== ein Datensatz über die verschiedenen Tabellen eingefügt
        end;
    end;                                            
  finally
    LThumbMemory.Free;                      
    FreeAndNil(BJpeg);
    FreeAndNil(BMap);
    FreeAndNil(LPicture);
  end;
end;
In der 2. Prozedur wird die Iteration durch die Pfadliste begonnen, wobei beim 2. Durchlauf eine AV ausgelöst wird, wenn LThumbMemory geleert werden soll. Wie aber ersichtlich ist, wiird LThumbMemory erst nach getaner Arbeit freigegeben.
Da ich LThumbMemory als Parameter übergebe, kamm mir die Idee, Firedac gäbe den Stream nach getaner Arbeit frei. Das aber kannnicht sein, da ein Probelauf schonmal funktioniert hatte.

Gruss
Delbor

Sir Rufo 10. Mär 2016 15:05

AW: Parameter unter Firedac
 
Ersichtlich ist da gar nichts, denn wir können nicht sehen, was in
Delphi-Quellcode:
BildInsertQuery
mit dem Stream passiert.

BTW
  • Diese Kopierorgie mit Picture, Bitmap, JpegImage, Stream ist schon sehr abstrus und könnte bequem auf ein Picture und JpegImage reduziert werden
  • Eine GUID als StringStream ist auch sehr merkwürdig

Delbor 10. Mär 2016 15:50

AW: Parameter unter Firedac
 
Hi Sir Rufo
Zitat:

Ersichtlich ist da gar nichts, denn wir können nicht sehen, was in BildInsertQuery mit dem Stream passiert.
Delphi-Quellcode:
function TFDMySQLDml.BildInsertQuery(LThumbMemory: TMemoryStream; FolderId: TStringstream): integer;
  var SQLString: string;
begin
  SQLString := 'Insert Into Bildtabelle(Thumbnail, FolderID) Values (:LThumbMemory, :FolderID)';
  FDQueryMain.SQL.Text := SQLString;
  FDQueryMain.Params[0].AsStream := LThumbMemory;
  FDQueryMain.Params[1].AsStream := FolderId;
  FDQueryMain.ExecSQL(false);
  if FDQueryMain.Active then
     FDQueryMain.Close;
  SQLString := 'Select Last_Insert_ID()AS LastID';
  FDQueryMain.SQL.Text := SQLString;
  FDQueryMain.Open;
  if not FDQueryMain.IsEmpty then
    result := FDQueryMain.FieldByName('LastID').AsInteger;     //
end;
Wie gesagt: Im ersten Durchlauf scheint der Stream FolderId akzeptiert zu werden - ExecSQL läuft scheinbar(?) problemlos ab.
Soll dann im zweiten Durchlauf LThumbmemory neu befüllt werden, muss es erstmal geleert werden. Ich könnte wohl auch die Position zurücksetzen, dass hätte aber zur Folge, dass Reste des vorigen Bildes angezeigt werden, wenn das aktuelle Bild kleiner ist.
Zitat:

Diese Kopierorgie mit Picture, Bitmap, JpegImage, Stream ist schon sehr abstrus und könnte bequem auf ein Picture und JpegImage reduziert werden
Diese Kopierorgie macht durchaus Sinn - das Jpeg(LThumbnail) dient der Navigation in der Datenbank. Diese Dinger bringen es auf gerade mal 1.2 KB. Grössere Bilder würden die Navigation deutlich verlangsamen. Die Bitmap brauche zum einen, um ein Thumbnail im BMP-Format herzustellen. Ausserdem wollte ich sie ursprünglich auch in der DB speichern, tue dies aber aktuell noch nicht, da die Dinger gut dreimal grösser sind. Benötigt werden die Bitmaps für die Bearbeitung der Bilder. Und zu guter letzt werden damit Jpegs in "normaler" Grösse hergestellt.
Zitat:

Eine GUID als StringStream ist auch sehr merkwürdig
Da ich bei der Erzeugung der GUID diese in eine Stringvariable speichere (Embarcadero-Vorschlag), schien mir dies naheliegend.
Embarcadero äussert sich nicht darüber (oder ich habs gründlich überlesen), wie ein GUID binär gespeichert werden kann.
Einzig TPictur ist eventuell überflüssig; bei der Erstellung der Procedur schien es mir aber der einfachste weg zu sein, ein Bild zu laden. Das wäre allenfalls zu optimieren...

Gruss
Delbor

PS:
Delphi-Quellcode:
LPicture.LoadFromFile(FPathList[i]);
Das lädt erstmal ein NEF-Bild. Und davon brauche ich eine Bitmap und ein Jpeg. Nef-Bilder könnten auch mit WICImage geladen werden, aber das hab ich wieder verworfen. Soweit ich mmich erinnere, sind die WicImage-Bilder nicht mehr im Original vorhanden, wenn sie erstmal, in was auch immer, umgewamdelt wurden.

Sir Rufo 10. Mär 2016 16:00

AW: Parameter unter Firedac
 
Siehe englische Hilfeseite zu
Delphi-Quellcode:
TFDParam.AsStream

Zitat:

The assigned
Delphi-Quellcode:
TStream
object will be owned by this
Delphi-Quellcode:
TFDParam
.
Das herunterskalieren auf ein JPEG ist ja ok, aber diese wilde hin- und herkopiere ist zum großen Teil überflüssig.

Zumal ein
Delphi-Quellcode:
FDQueryMain.Params[0].Assign( MyImage );
das auch erledigt. Also ist der Stream schonmal komplett überflüssig.

Eine GUID ist auch nur eine Bytefolge und kann mit
Delphi-Quellcode:
System.Sysutils.TGUIDHelper
ganz gemütlich in ein ByteArray geschoben werden.

Delbor 10. Mär 2016 16:32

AW: Parameter unter Firedac
 
Hi SirRufo
Zitat:

Eine GUID ist auch nur eine Bytefolge und kann mit System.Sysutils.TGUIDHelper ganz gemütlich in ein ByteArray geschoben werden.
Danke für die Info!! Auf jeden Fall auf den von mir besuchten Seiten habe ich nichts über TGUIDHelper entdecken können. Wobei natürlich wie immer gilt: wegen der Fülle von Infos kann auch mal was überlesen werden.
Zitat:

Zumal ein FDQueryMain.Params[0].Assign( MyImage ); das auch erledigt. Also ist der Stream schonmal komplett überflüssig.
Eventuell dämliche Nachfrage: Was erledigt das auch? Das Einfügen des Bildes in einer für die DB akzeptablen Grösse?
Wenn ich eine Bitmap erstelle und diese bearbeite, will ich sie so, wie ich sie bearbeitet habe, in der DB. Ansonsten müsste ich ein Bild jedesmal neu als Bitmap erstellen und neu bearbeiten, wenn Bedarf besteht.

Gruss
Delbor

Sir Rufo 10. Mär 2016 16:40

AW: Parameter unter Firedac
 
Statt Grafik in Stream und Stream an Parameter einfach nur Grafik per Assign an den Parameter.

Delbor 10. Mär 2016 16:49

AW: Parameter unter Firedac
 
Hi Sir Rufo
Erstmal danke für den Tip:
Zitat:

Statt Grafik in Stream und Stream an Parameter einfach nur Grafik per Assign an den Parameter.
Und nun lass mich raten: da Grafiken binäre Daten sind, hätte das auch unter DBExpress funktioniert?

Gruss
Delbor

Sir Rufo 10. Mär 2016 16:51

AW: Parameter unter Firedac
 
Das funktioniert mit allen Klassen, die von
Delphi-Quellcode:
TPersistent
abgeleitet sind und
Delphi-Quellcode:
IStreamPersist
implementieren.

Und
Delphi-Quellcode:
TGraphic
erfüllt dieses Kriterium - siehe: Delphi-Referenz durchsuchenTGraphic

Korrektur:
Delphi-Quellcode:
TStrings
wird beim Assign gesondert behandelt und nicht über
Delphi-Quellcode:
IStreamPersist

Delbor 11. Mär 2016 13:14

AW: Parameter unter Firedac
 
Hi zusammen

In Bezug auf den GUID tut sich noch ein Problemm auf. Um mich selbst zu zitieren:
Zitat:

Allerdings ist mir ein Designfehler unterlaufen. Ich habe das Feld für den GUID der Bildtabelle verpasst, aber eigentlich gehört das Ding in die Kategorientabelle - die enthält "Kategorien" (diesen Namen habe ich seinerzeit falsch gewählt), die jedoch eigentlich den Ordnernamen auf der Festplatte entsprechen. Diese Ordner enthalten meist Fotos, die bei einem bestimmten Ereignis entstanden sind, können aber auch solche enthalten, die sich auf mehrere Ereignisse beziehen.
  • Grundsätzlich kann ich über ein Eingabefeld eine neue Kategorie erzeugen. Die muss dann ichts mit einem Ordnernamen gemein haben.
  • Die Kategorien können in der DB jederzeit geändert werden. Das wird vor allem der Fall sein, wenn sich die Rohdaten im Quellordner auf mehrere Ereignisse beziehen.
  • Auf diese Weise haben dann Bilder in der DB plötzlich keinen zugehörigen Rohdaten-Ordner mehr auf der Festplatte
Das bedeutet aber, dass ich so vorgehen muss, wie ich es bisher umgesetzt habe - die eigentliche Bildtabelle enthält neben den 3 Blobfeldern auch ein Feld für den GUID.
Und das wiederum widerspricht eigentlich den Normalisierungsregeln: Ich hab jetzt nur mal testweise Bilder aus einem Ordner in die DB aufgenommen - 444 Stück, und jedem wird der selbe GUID zugeordnet.

Wie liesse sich das lösen?

Gruss
Delbor


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:48 Uhr.
Seite 3 von 4     123 4      

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