Особливості використання BLOB полів в dbExpress на прикладі MySQL
Використовувати нові компоненти dbExpress зручно. Однак прикметник «нові» приносить не тільки радість ... Рішення виникаючих проблем буває затягується на довгі години і дні. На допомогу Internet жаль сподіватися не доводиться, тому що інформації по dbExpress там ні так багато. Одна з цих проблем - робота з BLOB полями. Використовувати нативний SQL для роботи з BLOB не завжди можливо, тому потрібно застосовувати інші, альтернативні способи.
Для роботи з BLOB полями в Delphi є кілька класів:
- TBlobStream;
- TClientBlobStream;
- TBlobField;
- TGraphicField;
- TMemoField;
Також сюди можна віднести функцію TCustomClientDataSet.CreateBlobStream, але вона реалізована за допомогою класу TClientBlobStream. Класи TGraphicField і TMemoField є похідними від TBlobField. TBlobStream не підходить для роботи з dbExpress, а застосовується тільки при маніпулюванні даними через BDE.
Таким чином для роботи з BLOB-полями через dbExpress залишаються два ключових класу: TBlobField і TClientBlobStream. Отже можливо два, принципово різних, способи отримати доступ до BLOB-полів: через потоки і через властивості об'єкта. Як зазначено в довідці при роботі з BLOB-полями взагалі і dbExpress зокрема досить зручними виявляються змінні типу String.
Дійсно, максимальний розмір даних, що зберігаються в змінних даного типу становить 2 Гб, що дорівнює максимальному розміру BLOB-поля в MySQL (3.23.47). Рядки досить зручні для роботи з потоками, а також існує досить багато функцій для роботи з ними. Проблем при роботі з BLOB-полями також існує дві: читання даних і їх запис. Розглянемо кожен з можливих варіантів.
Проблема №1. Читання даних з BLOB-поля
Для роботи з BLOB-полями необхідно привласнити властивості TCustomClientDataSet.FetchOnDemand значення True, а також необхідно уважно вивчити властивість Options параметр poFetchBlobsOnDemand. Дані настройки потрібні для того, щоб отримувати дані з BLOB-поля в клієнтську програму. Завантажити дані можна використовуючи метод FetchBlobs.
Використання властивості TDataSet.FieldValues
Використання властивості TBlobField.Value
Проблема №2. Запис даних в BLOB-поле.
При записи даних в BLOB-поле необхідно враховувати, що для внесення змін одного методу Post недостатньо. Для пересилання даних в таблицю після методу Post необхідно викликати метод TCustomClientDataSet.ApplyUpdates. Разом з цим методом корисно використовувати властивість TCustomClientDataSet.ChangeCount, яке містить кількість змін внесених користувачем. У довідковій системі Delphi міститься приклад як спільно використовувати цю властивість і метод ApplyUpdates.
Перед створенням потоку необхідно обов'язково викликати метод FetchBlobs для завантаження даних з BLOB-поля, інакше виникає помилка. При роботі з полем використовуючи потік, необхідно дотримуватися правила:
Одна запис - один потік.
Якщо необхідно обробити новий запис, то потік необхідно створювати заново. Природно потрібно не забувати вчасно знищувати створені потоки.
З незрозумілих причин цей код не працює. Точніше дані в Stream передаються, але в базу не записуються. При цьому ніяких помилок не видається (може це bug, а може щось в даному коді не враховано). У зв'язку з цим, якщо необхідно використання потоків, слід створити проміжний потік, потім завантажити в нього дані, а потім ці дані перекинути в строкову змінну, яку в подальшому занести в базу. Цей спосіб не є найоптимальнішим, але працює безвідмовно.