Записать/прочитать массив из BLOB

Обсуждение возникших проблем, предложений и ошибок MyDAC компонентов
Закрыто
Sanya111
Сообщения: 26
Зарегистрирован: Пн 02 июл 2012 14:07

Записать/прочитать массив из BLOB

Сообщение Sanya111 » Чт 27 июн 2013 08:29

Добрый день.
Извините, пожалуйста, меня за мои знания.
Я пытался самостоятельно найти информацию в сети и читал документацию MyDAC, но рабочего кода я к сожалению не составил.
Подскажите, пожалуйста, как грамотно записать динамический массив чисел и строку в поле BLOB и затем прочитать эти данные.
Могут ли возникнуть какие-либо проблемы на 32/64 разрядных системах или мой код будет работать и там и там?

Создаю таблицу.

Код: Выделить всё

Form1.MyConnection1.ExecSQL('create table if not exists GR (n_id INTEGER NOT NULL AUTO_INCREMENT,'
+'t_id BLOB,'  
+'primary key (n_id))'
+ 'ENGINE = INNODB', []); // INNODB для поддержки транзакций
Засписываю массив из чисел в BLOB

Код: Выделить всё

procedure TForm1.Button1Click(Sender: TObject);var
i: integer;
Matrix: array of integer;
Stream: TMemoryStream;

begin
SetLength(Matrix,10);
for i:=0 to 9 do begin
Matrix[i]:=i;
end;

Stream:= TMemoryStream.Create;

try
Stream.Size:= Length(Matrix) * SizeOf(integer);
Stream.Position := 0;
Stream.Write(Matrix[0], Stream.Size);

Form1.MyQuery1.SQL.Text := 'INSERT INTO gr (t_id) VALUES (:t_id)';
Form1.MyQuery1.Prepare; 
if not Form1.MyConnection1.InTransaction then
Form1.MyConnection1.StartTransaction;
  
try
for i:=0 to 4 do begin
Form1.MyQuery1.ParamByName('t_id').LoadFromStream(Stream, ftBlob);
Form1.MyQuery1.Execute;
end;
Form1.MyConnection1.Commit;
except
Form1.MyConnection1.Rollback;
raise;
end;

finally
Stream.free;
Matrix:=nil;
end;

end;
Открываю BLOB поле в dbForgeStudio, но как убедиться что правильно записались данные?
Изображение


А с этим кодом не знаю что делать, пытаюсь прочитать BLOB.
Ошибка [dcc32 Error] Unit1.pas(80175): E2003 Undeclared identifier: 'SaveToStream'
Так же не могу понять в как поменять размер массива в который будет идти запись.

Код: Выделить всё

Stream:= TMemoryStream.Create;
Form1.MyQuery1.SQL.Text:= 'select * from gr where n_id=:dname';
Form1.MyQuery1.ParamByName('dname').AsInteger :=1;
Form1.MyQuery1.Open;
while not Form1.MyQuery1.Eof do
begin
Form1.MyQuery1.FieldByName('t_id').SaveToStream(Stream);
Form1.MyQuery1.Next;
end;
Form1.MyQuery1.Close;
Stream.free;
Записываю строку в BLOB

Код: Выделить всё

procedure TForm1.Button1Click(Sender: TObject);var
i: integer;
s: string;
Stream: TMemoryStream;

begin
s:='HELLO WORLD'

Stream:= TMemoryStream.Create;

try
Stream.Write(s[1],Length(s)* SizeOf(char)); 

Form1.MyQuery1.SQL.Text := 'INSERT INTO gr (t_id) VALUES (:t_id)';
Form1.MyQuery1.Prepare; 
if not Form1.MyConnection1.InTransaction then
Form1.MyConnection1.StartTransaction;
  
try
for i:=0 to 4 do begin
Form1.MyQuery1.ParamByName('t_id').LoadFromStream(Stream, ftBlob);
Form1.MyQuery1.Execute;
end;
Form1.MyConnection1.Commit;
except
Form1.MyConnection1.Rollback;
raise;
end;

finally
Stream.free;
end;

end;
При просмотре в dbForgeStudio я могу убедиться что правильно записались данные
Изображение

DemetrionQ
Devart Team
Сообщения: 51
Зарегистрирован: Пн 28 янв 2013 11:54

Re: Записать/прочитать массив из BLOB

Сообщение DemetrionQ » Вт 02 июл 2013 11:31

Здравствуйте.

1) Вы правильно использовали TMemoryStream при работе с параметрами. На предоставленном вами снимке просмотрщика данных видно, что массив из десяти integer чисел сохранился корректно - именно такой последовательностью байт массив хранился в памяти вашего приложения.

2) Для копирования данных из TStream объектов в TField и обратно, вы можете использовать следующий код

Код: Выделить всё

  TBlobField(MyQuery1.FieldByName('t_id')).LoadFromStream(Stream);
  TBlobField(MyQuery1.FieldByName('t_id')).SaveToStream(Stream);
Для установки длины динамических массивов используйте метод SetLength (вы его уже использовали в своём коде). После загрузки данных из TField в TStream вы можете определить требуемую длину integer массива по формуле

Код: Выделить всё

  Stream.Size div SizeOf(integer)
3) Для сохранении и чтении строк из Blob полей используйте TParam.AsString и TField.AsString, например:

Код: Выделить всё

  MyQuery1.FieldByName('t_id').AsString := 'HELLO WORLD';

Sanya111
Сообщения: 26
Зарегистрирован: Пн 02 июл 2012 14:07

Re: Записать/прочитать массив из BLOB

Сообщение Sanya111 » Вт 02 июл 2013 15:19

Составил код который читает массив чисел из BLOB поля и выводит в TMemo для наглядности.
Надеюсь я учел все нюансы.

Код: Выделить всё

procedure TForm1.Button21Click(Sender: TObject);
var
i: integer;
Matrix: array of integer;
Stream: TMemoryStream;
begin

Stream:= TMemoryStream.Create;
Form1.MyQuery1.SQL.Text:= 'select * from gr where n_id=:dname';
Form1.MyQuery1.ParamByName('dname').AsInteger :=1;
Form1.MyQuery1.Open;
while not Form1.MyQuery1.Eof do
begin

try
TBlobField(Form1.MyQuery1.FieldByName('t_id')).SaveToStream(Stream);
SetLength(matrix,Stream.Size div SizeOf(integer));

Stream.Position := 0;
Stream.read(Matrix[0], Stream.Size);

for i:=0 to Length(Matrix)-1 do begin
memo1.lines.add(inttostr(matrix[i]));
Application.ProcessMessages;
end;

Stream.clear;
matrix:=nil;

except
Stream.clear;
matrix:=nil;
end;

Form1.MyQuery1.Next;
end;
Form1.MyQuery1.Close;

matrix:=nil;
Stream.free;
end;
DemetrionQ, большое за помощь, Вы мне сильно помогли!

DemetrionQ
Devart Team
Сообщения: 51
Зарегистрирован: Пн 28 янв 2013 11:54

Re: Записать/прочитать массив из BLOB

Сообщение DemetrionQ » Ср 03 июл 2013 09:49

Здравствуйте.

Что бы гарантировать освобождения TMemoryStream объекта, вы можете включить в ваш код try finally инструкцию следующим образом

Код: Выделить всё

Stream:= TMemoryStream.Create;
try
  Form1.MyQuery1.SQL.Text:= 'select * from gr where n_id=:dname';
...
...
...
  Form1.MyQuery1.Close;

  matrix:=nil;
finally
  Stream.free;
end;
В остальном ваш код корректен и вы можете его использовать. Если возникнут ещё вопросы, обращайтесь.

Sanya111
Сообщения: 26
Зарегистрирован: Пн 02 июл 2012 14:07

Re: Записать/прочитать массив из BLOB

Сообщение Sanya111 » Ср 03 июл 2013 12:02

Огромное спасибо за помощь!!

Закрыто