Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
Доброго времени суток!

У меня в проекте есть модуль (назовем его PkBase), в котором обрабатываются вызовы хранимых процедур из БД Oracle. В рабочей форме есть переменная этого класса. В самом PkBase есть процедура обращения в БД одним из возвращаемых параметров которой есть переменная типа TOraLob. Выполняю её, ошибок нет. Полученный блоб сохраняю в файл. Но когда приходит очередь закрывать форму, то вываливается ошибка

К сообщению приложен файл. Размер - 6Kb
1 ноя 18, 18:58    [21721868]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
Я просто нигде не найду пример с возвратом блоба из хп. Что я делаю не правильно?
1 ноя 18, 19:00    [21721870]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Квейд
Member

Откуда: Kyiv, Ukraine
Сообщений: 5095
Как пробовал?
1 ноя 18, 19:10    [21721879]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
Вот класс для общения с БД
unit PkBase;

interface

uses Classes, SysUtils, Ora, OraPackage, System.Variants, OraUtils,
  System.Generics.Collections, Data.DB, OraClasses;

TPkBase = class(TCustomOraPackage)
  private
    FSession: TOraSession;
    procedure GetStoreProc;
    function GetSession: TOraSession;
    procedure SetSession(AValue: TOraSession);
  protected
    StoredProc: TOraStoredProc;
  published
    property Session: TOraSession read GetSession write SetSession;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    //òóò èäóò âûçîâû ïðîöåäóð è ôóíêöèé
   ...
   procedure InsertBlob(const PFileName: string; const PFKey: Double; const PBlob: TOraLob);
   ...
   procedure GetBlob(const PFileKey: Double; out PFileName: string; out PBlob: TOraLob);
   ...
  end;

implementation

constructor TPkBase.Create(AOwner: TComponent);
begin
  inherited;
  StoredProc := TOraStoredProc.Create(nil);
end;

destructor TPkBase.Destroy;
begin
  if Assigned(StoredProc) then
    FreeAndNil(StoredProc);
  inherited;
end;

procedure TPkBase.GetStoreProc;
begin
  StoredProc.Session := Session;
  StoredProc.StoredProcName := '';
  StoredProc.Prepared;
end;

procedure TPkBase.InsertBlob(const PFileName: string; const PFKey: Double; const PBlob: TOraLob);
begin
  GetStoreProc;
  StoredProc.StoredProcName := '<PKG>.INSERT_BLOB';
  StoredProc.Prepare;
  StoredProc.ParamByName('P_FULLNAME').AsString := PFileName;
  StoredProc.ParamByName('P_FKEY').AsFloat := PFKey;
  StoredProc.ParamByName('P_BLOB').AsOraBlob := PBlob;
  StoredProc.Execute;
end;

procedure TPkBase.GetBlob(const PFileKey: Double; out PFileName: string; out PBlob: TOraLob);
begin
  GetStoreProc;
  StoredProc.StoredProcName := '<PKG>.GET_BLOB';
  StoredProc.Prepare;
  StoredProc.ParamByName('P_FKEY').AsFloat := PFileKey;
  StoredProc.Execute;
  PFileName := StoredProc.ParamByName('P_FULLNAME').AsString;
  PBlob := StoredProc.ParamByName('P_BLOB').AsOraBlob;
  //StoredProc.ParamByName('P_BLOB').AsOraBlob.FreeBlob;
end;


Теперь вызов

unit FileReestr;

interface

uses
  ...
  PkBase;

type
  TfrmFileReestr = class(TfrmMDIForm)  //родитель - мой класс, обычная форма с FormStyle=fsMDIChild
    ...
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    ...
    procedure actUnloadFilesExecute(Sender: TObject);
  private
    FPkBase: TPkBase;

var
  frmFileReestr: TfrmFileReestr;

implementation

{$R *.DFM}

procedure TfrmFileReestr.FormCreate(Sender: TObject);
begin
  inherited;
  ...
  FPkBase := TPkMop.Create(nil);
  FPkBase.Session := DefSession;
end;

procedure TfrmFileReestr.FormDestroy(Sender: TObject);
begin
  if Assigned(FPkBase) then
    FreeAndNil(FPkBase);
  inherited;
end;

procedure TfrmFileReestr.actUnloadFilesExecute(Sender: TObject);
Var
  LLob: TOraLob;
  LFileName, LSaveDir: string;
  LSaveDialog: TSaveDialog;
begin
  try
    LSaveDialog := TSaveDialog.Create(nil);
    try
      LSaveDir := ExtractFileDir(Application.ExeName) + '\';
      LLob := TOraLob.Create(DefSession.OCISvcCtx);
      LLob.AllocLob;
      LLob.CreateTemporary(ltBlob);
      FPkBase.GetBlob(FFileKey, LFileName, LLob);
      LSaveDialog.InitialDir := LSaveDir;
      LSaveDialog.FileName := LFileName;
      LSaveDialog.Filter := '*|*';
      if LSaveDialog.Execute then
        LLob.SaveToFile(LSaveDialog.FileName);
      MessageDlg('Файл успішно вивантажено!', mtInformation, [mbOK], 0);
    except
      on E: Exception do
      begin
        Application.ShowException(E);
      end;
    end;
  finally
    if Assigned(LSaveDialog) then
      FreeAndNil(LSaveDialog);
    if Assigned(LLob) then
      LLob.Free;
  end;
end;

Вызов отрабатывает нормально, но при закрытии формы frmFileReestr вылетает ошибка. После нее все нормально, приложение продолжает работать.

Среда Embarcadero Berlin, компоненты ODAC, база Oracle 11.2.0.4.0
2 ноя 18, 10:14    [21722202]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
ma1tus
Member

Откуда:
Сообщений: 581
Имхо, здесь уничтожается
Леонов Юрий
LLob.Free;
не этот объект
Леонов Юрий
procedure TfrmFileReestr.actUnloadFilesExecute(Sender: TObject);
Var
  LLob: TOraLob;
Не создавать, а просто возвращать TOraLob из TPkBase.GetBlob - не?

+ ...
Леонов Юрий
LLob.AllocLob;
CreateTemporary сам это делает...
2 ноя 18, 11:04    [21722267]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
ma1tus
Имхо, здесь уничтожается
Леонов Юрий
LLob.Free;
не этот объект

А какой должен уничтожаться?

ma1tus
Не создавать, а просто возвращать TOraLob из TPkBase.GetBlob - не?


У меня 2 параметра функцией возвращается, имя файла и собственно блоб, оба нужны в процедуре.

Ошибка вылетает тут

procedure TfrmFileReestr.FormDestroy(Sender: TObject);
begin
  if Assigned(FPkBase) then
    FreeAndNil(FPkBase); //вот тут вылетает
  inherited;
end;
2 ноя 18, 11:30    [21722317]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Квейд
Member

Откуда: Kyiv, Ukraine
Сообщений: 5095
Леонов Юрий
    if Assigned(LSaveDialog) then
      FreeAndNil(LSaveDialog);

Выделенное лишнее
2 ноя 18, 11:45    [21722333]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
ma1tus
Member

Откуда:
Сообщений: 581
Леонов Юрий
А какой должен уничтожаться?
вот этот...
LLob := TOraLob.Create(DefSession.OCISvcCtx);

Процедура TPkBase.GetBlob, через параметр
out PBlob: TOraLob
записывает в LLob свой объект, а ваш, ручками созданный по этому адресу - утекает...
2 ноя 18, 11:53    [21722360]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
Квейд
Леонов Юрий
    if Assigned(LSaveDialog) then
      FreeAndNil(LSaveDialog);

Выделенное лишнее


Это не существенно, привычка проверять
2 ноя 18, 12:23    [21722408]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
ma1tus
Леонов Юрий
А какой должен уничтожаться?
вот этот...
LLob := TOraLob.Create(DefSession.OCISvcCtx);


А я какой уничтожаю?

ma1tus
Процедура TPkBase.GetBlob, через параметр
out PBlob: TOraLob
записывает в LLob свой объект, а ваш, ручками созданный по этому адресу - утекает...


Я наверное чего-то недопонял... Я создаю LLob, записываю процедурой в него значение, сохраняю из этого же LLob в файл и потом этот же LLob я уничтожаю... Что-то я запутался. Можете привести пример, как должно быть?
2 ноя 18, 12:27    [21722416]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
goldmi45
Member

Откуда:
Сообщений: 1055
procedure TfrmFileReestr.actUnloadFilesExecute(Sender: TObject);
Var
  LLob: TOraLob;
  LFileName, LSaveDir: string;
  LSaveDialog: TSaveDialog;
begin
  try
    LSaveDialog := TSaveDialog.Create(nil);
    try
      LSaveDir := ExtractFileDir(Application.ExeName) + '\';
      LLob := TOraLob.Create(DefSession.OCISvcCtx); /// Создали свой LLob
      LLob.AllocLob;
      LLob.CreateTemporary(ltBlob);
      FPkBase.GetBlob(FFileKey, LFileName, LLob); /// Перезаписали LLob (стал новый LLob, а старый потеряли)
    ....
    except
      on E: Exception do
      begin
        Application.ShowException(E);
      end;
    end;
  finally
    if Assigned(LSaveDialog) then
      FreeAndNil(LSaveDialog);
    if Assigned(LLob) then
      LLob.Free; /// Уничтожили тот, который получили из GetBlob, а который создавали, утёк
  end;
end;
2 ноя 18, 13:14    [21722470]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
goldmi45,

как правильно тогда сделать? Я же не могу не создавая экземпляр что-то в него писать
2 ноя 18, 13:20    [21722477]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
goldmi45
Member

Откуда:
Сообщений: 1055
Леонов Юрий
goldmi45,

как правильно тогда сделать? Я же не могу не создавая экземпляр что-то в него писать

Почему? Разве такой код не работает:
Var
  LLob: TOraLob;
  LFileName, LSaveDir: string;
  LSaveDialog: TSaveDialog;
begin
  try
    LSaveDialog := TSaveDialog.Create(nil);
    try
      LSaveDir := ExtractFileDir(Application.ExeName) + '\';
      FPkBase.GetBlob(FFileKey, LFileName, LLob);
      LSaveDialog.InitialDir := LSaveDir;
      LSaveDialog.FileName := LFileName;
      LSaveDialog.Filter := '*|*';
      if LSaveDialog.Execute then
        LLob.SaveToFile(LSaveDialog.FileName);
      MessageDlg('Файл успішно вивантажено!', mtInformation, [mbOK], 0);
    except
      on E: Exception do
      begin
        Application.ShowException(E);
      end;
    end;
  finally
    if Assigned(LSaveDialog) then
      FreeAndNil(LSaveDialog);
    if Assigned(LLob) then
      LLob.Free;
  end;
end;
2 ноя 18, 13:23    [21722481]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
goldmi45
Member

Откуда:
Сообщений: 1055
Леонов Юрий,

out-параметр и var-параметр вообще-то отличаются.
У вас out
2 ноя 18, 13:25    [21722482]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
goldmi45,

да в этом коде все устраивает, не устраивает только ошибка, которая вылетает по закрытии формы
2 ноя 18, 13:44    [21722495]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
goldmi45
Леонов Юрий,

out-параметр и var-параметр вообще-то отличаются.
У вас out


Разницы никакой для этого случая
2 ноя 18, 13:47    [21722501]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
goldmi45
Member

Откуда:
Сообщений: 1055
Леонов Юрий,

хм, вроде как не нужно даже уничтожать экземпляр LLob: TOraLob в процедуре TfrmFileReestr.actUnloadFilesExecute. Он уничтожится вместе с экземпляром StoredProc
2 ноя 18, 13:51    [21722504]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
goldmi45
Леонов Юрий,

хм, вроде как не нужно даже уничтожать экземпляр LLob: TOraLob в процедуре TfrmFileReestr.actUnloadFilesExecute. Он уничтожится вместе с экземпляром StoredProc


Интересно, а если я повторно нажму кнопку, что тогда будет? Мусорная куча, пока я не закрою форму?
2 ноя 18, 14:04    [21722513]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
goldmi45
Member

Откуда:
Сообщений: 1055
Леонов Юрий
Интересно, а если я повторно нажму кнопку, что тогда будет? Мусорная куча, пока я не закрою форму?

Вы освобождаете не свою переменную. В этом и есть ошибка. Ну а почему не попробовать не освобождать? Вы же параметры у StoredProc тоже не освобождаете.
2 ноя 18, 14:09    [21722517]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
goldmi45
Леонов Юрий
Интересно, а если я повторно нажму кнопку, что тогда будет? Мусорная куча, пока я не закрою форму?

Вы освобождаете не свою переменную. В этом и есть ошибка. Ну а почему не попробовать не освобождать? Вы же параметры у StoredProc тоже не освобождаете.


Таки да, закомментил удаление LLob и все наладилось. Не учел момент, что переопределяется адрес переменной.
Спасибо, растолковали))
2 ноя 18, 14:32    [21722537]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие формы и TOraLob  [new]
Леонов Юрий
Member

Откуда: Украина, Харьков
Сообщений: 447
Финальный вариант вызова выглядит так, если кому будет нужно:
procedure TfrmFileReestr.actUnloadFilesExecute(Sender: TObject);
Var
  LLob: TOraLob;
  LFileName, LSaveDir: string;
  LSaveDialog: TSaveDialog;
begin
  try
    LSaveDialog := TSaveDialog.Create(nil);
    try
      LSaveDir := ExtractFileDir(Application.ExeName) + '\';
      FPkBase.GetBlob(FFileKey, LFileName, LLob);
      LSaveDialog.InitialDir := LSaveDir;
      LSaveDialog.FileName := LFileName;
      LSaveDialog.Filter := '*|*';
      if LSaveDialog.Execute then
        LLob.SaveToFile(LSaveDialog.FileName);
      MessageDlg('Файл успішно вивантажено!', mtInformation, [mbOK], 0);
    except
      on E: Exception do
      begin
        Application.ShowException(E);
      end;
    end;
  finally
    if Assigned(LSaveDialog) then
      FreeAndNil(LSaveDialog);
  end;
end;

Получается, что создавать переменную типа и уничтожать не надо.
Огромная благодарность goldmi45!
5 ноя 18, 16:24    [21724316]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить