Использование компонентов IBX в Builder 6 С++
Модератор: kdv
Использование компонентов IBX в Builder 6 С++
Здравствуйте. Прошу направить меня по правильному пути при использовании компонентов IBxxx (InterBase):
1. Интересует возможность редактирования записей в компоненте IBTable. Работает также, как и Table?
2. Может ли компонент IBTable отображать таблицу, если в ней есть поля содержащие "ссылки" на другие таблицы? Т.е. в данном поле хранятся лишь индексы каких-то данных, которые, соответственно, хранятся в другой таблице. Или же необходимо использовать IBQuery и потом обрабатывать самостоятельно, в том числе и редактирование. Как еще варианты?
Спасибо.
1. Интересует возможность редактирования записей в компоненте IBTable. Работает также, как и Table?
2. Может ли компонент IBTable отображать таблицу, если в ней есть поля содержащие "ссылки" на другие таблицы? Т.е. в данном поле хранятся лишь индексы каких-то данных, которые, соответственно, хранятся в другой таблице. Или же необходимо использовать IBQuery и потом обрабатывать самостоятельно, в том числе и редактирование. Как еще варианты?
Спасибо.
не надо IBTable. используй IBDataSet. читай
www.ibase.ru/devinfo/ibx.htm
www.ibase.ru/devinfo/ibx.htm
Большое спасибо. Многие возникающие вопросы там освещены.kdv писал(а):не надо IBTable. используй IBDataSet. читай
www.ibase.ru/devinfo/ibx.htm
Есть еще вопрос, как правильно осуществить следующее.
Имеем одну главную таблицу, в которой многие поля являются лишь ссылками (индексами) к другим таблицам. Для добавления данных создается форма, на которой для внесения данных по определенным полям используем компонент ComboBox, который должен выводить список из сопутствующих таблиц (расшифровка индекса).
Как правильно вносить данные в список ComboBox'a - кидаем DataSet по заданной таблице, пробегаемся по каждой строчке в поле расшифровки индекса и заносим в ComboBox.Items? Или есть что-то автоматическое для таких случаев? Замечу, что нам нужно для приложения получить (после выбора) не описание индекса, а сам индекс, для использования его в основной таблице.
-
- Заслуженный разработчик
- Сообщения: 1436
- Зарегистрирован: 15 сен 2005, 09:05
Ответ на этот вопрос сильно зависит от размера "сопутствующих таблиц". Для малого размера (пара десятков записей) - нормально. Для большого
лично я бы сделал не полный список в ComboBox а скорее AutoComplete после того как пользователь наберет достаточное количество символов.
С другой стороны можно ведь справочник вытащить один раз в начале работы и закэшировать на клиенте...
лично я бы сделал не полный список в ComboBox а скорее AutoComplete после того как пользователь наберет достаточное количество символов.
С другой стороны можно ведь справочник вытащить один раз в начале работы и закэшировать на клиенте...
Можно и проще. LookupComboBox...Шмель писал(а): Как правильно вносить данные в список ComboBox'a - кидаем DataSet по заданной таблице, пробегаемся по каждой строчке в поле расшифровки индекса и заносим в ComboBox.Items? Или есть что-то автоматическое для таких случаев? Замечу, что нам нужно для приложения получить (после выбора) не описание индекса, а сам индекс, для использования его в основной таблице.
Здравствуйте. Споткнулся о стандартную ситуацию, но по неопытности не удается ее перешагнуть. Не хватает какого-то нюанса. Суть вопроса в следующем:
При работе с базой данных (InterBase, Builder C++) использую IBDataSet у которых имеются свойства SelectSQL и InsertSQL. Эти запросы используют параметры (:param), причем наборы параметров в этих SQL запросах различаются. С SelectSQL проблем не возникает - послушно работает, а вот когда пытаюсь присвоить значение для параметров из InsertSQL, вылазит сообщение, что такой параметр не известен. Что-то ещё нужно подкрутить? Где-то нужно указать, что скоро будет использоваться InsertSQL и сделать его "активным"?
Верен ли следующий алгоритм вставки:
1.IBDataSet.InsertSQL = ".. :param .. " - записали запрос
2.IBDataSet.Prepare() - проверили правильность запроса
3.IBDataSet.ParamByName("param") = ...
4.IBDataSet.Open
5.IBDataSet.Insert.
И еще. У IBDataSet есть поле GeneratorField, в котором заданный генератор привязывается к указанному полю по различным событиям, в том числе и по добавлению новых строчек. Эта связка нужна для того, чтобы не заморачиваться при вставке новых записей на задание параметра по указанию значения ключевого поля? Т.е. в InsertSQL не нужно указывать поле к которому привязан генератор?
Спасибо.
При работе с базой данных (InterBase, Builder C++) использую IBDataSet у которых имеются свойства SelectSQL и InsertSQL. Эти запросы используют параметры (:param), причем наборы параметров в этих SQL запросах различаются. С SelectSQL проблем не возникает - послушно работает, а вот когда пытаюсь присвоить значение для параметров из InsertSQL, вылазит сообщение, что такой параметр не известен. Что-то ещё нужно подкрутить? Где-то нужно указать, что скоро будет использоваться InsertSQL и сделать его "активным"?
Верен ли следующий алгоритм вставки:
1.IBDataSet.InsertSQL = ".. :param .. " - записали запрос
2.IBDataSet.Prepare() - проверили правильность запроса
3.IBDataSet.ParamByName("param") = ...
4.IBDataSet.Open
5.IBDataSet.Insert.
И еще. У IBDataSet есть поле GeneratorField, в котором заданный генератор привязывается к указанному полю по различным событиям, в том числе и по добавлению новых строчек. Эта связка нужна для того, чтобы не заморачиваться при вставке новых записей на задание параметра по указанию значения ключевого поля? Т.е. в InsertSQL не нужно указывать поле к которому привязан генератор?
Спасибо.
У InsertSQL нет параметров в обычном понимании, он формируется из полей SelectSQL. То есть, если тебе надо задавать значения полям при Insert, изволь их поселектить, после вызова метода Insert заполнить и сделать Post, т.е. отправить на сервер. Поле из GeneratorField в InsertSQL включать нужно, просто компонент сам его заполнит, обратившись к генератору "за кадром", скрытым запросом.
-
- Заслуженный разработчик
- Сообщения: 1436
- Зарегистрирован: 15 сен 2005, 09:05
Спасибо за ответы. Во многом (понимаю, что это условно) разобрался, многое уже сделал, однако появились ещё вопросы.
Как работая в Builder'e правильно организовать работу по контролю корректности данных (с точки зрения сервера БД):
1. Есть какие-то компоненты, которые могут получить сведения о том, что попытка записи отклонена как некорректный запрос по такой-то причине. Допустим при внесении новой записи прописываемая ссылка (для связанных таблиц) указывает на несуществующий элемент, или запись с таким же значением по уникальному полю уже существует. Получается, что мы должны получать от сервера БД сообщения об ошибках, возможно с указанием их типа.
2. Воспользоваться имеющимися стандартыми средствами и проверять все самим. Т.е. когда мы хотим добавить новую запись с помощью формы (дополнительного окна), то после выбора пользователя всех параметров и нажатия на "Добавить", программа:
а) открывает новую транзакцию типа snapshot
б) проверяет полностью на корректность вводимых данных для данного фиксированного образа БД
в) вносит новую запись в БД и выполняет Commit
г) проверяет в БД, что конфликта транзакций не произошло путем чтения записанных данных и проверке с исходными данными.
Как правильно? Спасибо.
PS: Если в транзакции выполняется последовательность записей, в конце мы выполняем Commit, а одна из множества операций не может быть выполнена (в частности из-за изменения в БД другой транзакцией). Что в этом случае происходит - полный откат?
Как работая в Builder'e правильно организовать работу по контролю корректности данных (с точки зрения сервера БД):
1. Есть какие-то компоненты, которые могут получить сведения о том, что попытка записи отклонена как некорректный запрос по такой-то причине. Допустим при внесении новой записи прописываемая ссылка (для связанных таблиц) указывает на несуществующий элемент, или запись с таким же значением по уникальному полю уже существует. Получается, что мы должны получать от сервера БД сообщения об ошибках, возможно с указанием их типа.
2. Воспользоваться имеющимися стандартыми средствами и проверять все самим. Т.е. когда мы хотим добавить новую запись с помощью формы (дополнительного окна), то после выбора пользователя всех параметров и нажатия на "Добавить", программа:
а) открывает новую транзакцию типа snapshot
б) проверяет полностью на корректность вводимых данных для данного фиксированного образа БД
в) вносит новую запись в БД и выполняет Commit
г) проверяет в БД, что конфликта транзакций не произошло путем чтения записанных данных и проверке с исходными данными.
Как правильно? Спасибо.
PS: Если в транзакции выполняется последовательность записей, в конце мы выполняем Commit, а одна из множества операций не может быть выполнена (в частности из-за изменения в БД другой транзакцией). Что в этом случае происходит - полный откат?
-
- Заслуженный разработчик
- Сообщения: 1436
- Зарегистрирован: 15 сен 2005, 09:05
1) Ошибка, конечно, вернется. Компоненты обычно при этом бросают исключение. Его можно ловить и реагировать.
2) Тоже неплохо, особенно если неверные данные отсекаются принудительно (скажем, выбор из списка вместо прямого ввода). Пункт г), вообще-то, бред.
Операции выполняются не во время COMMIT. Если какая-то операция не прошла, ты получишь ошибку сразу. Но commit после этого подтвердит все "прошедшие" операции. Правда, есть исключения и из этого правила...
2) Тоже неплохо, особенно если неверные данные отсекаются принудительно (скажем, выбор из списка вместо прямого ввода). Пункт г), вообще-то, бред.
Операции выполняются не во время COMMIT. Если какая-то операция не прошла, ты получишь ошибку сразу. Но commit после этого подтвердит все "прошедшие" операции. Правда, есть исключения и из этого правила...
Проверка делается очень просто:
1. На сервере для столбца указываешь внешний ключ на мастер-таблицу. Это знаешь как делать?
2. При попытке вставить/изменить запись с неверным кодом мастера, приложение схватит исключение. Ты должен его обработать (пример на Delphi):
'try
' DataSet.Post;
'exception
' on E: Exception do
' MessageBox(E.Message, mtError, [mbOk], 0);
'end;
Если хочешь, можешь отлавливать какие-то конкретные исключения (например, EDatabaseException).
Когда произойдет исключение, набор останется в том же состоянии, в котором был (dsInsert или dsEdit).
3. Про свой вариант 2 забудь. Навсегда.
4. Могу ошибаться, но при Commit'е не бывает исключений.
Если запрос не может быть выполнен, он просто не выполняется. Транзакция при этом продолжает работать.
1. На сервере для столбца указываешь внешний ключ на мастер-таблицу. Это знаешь как делать?
2. При попытке вставить/изменить запись с неверным кодом мастера, приложение схватит исключение. Ты должен его обработать (пример на Delphi):
'try
' DataSet.Post;
'exception
' on E: Exception do
' MessageBox(E.Message, mtError, [mbOk], 0);
'end;
Если хочешь, можешь отлавливать какие-то конкретные исключения (например, EDatabaseException).
Когда произойдет исключение, набор останется в том же состоянии, в котором был (dsInsert или dsEdit).
3. Про свой вариант 2 забудь. Навсегда.
4. Могу ошибаться, но при Commit'е не бывает исключений.
Если запрос не может быть выполнен, он просто не выполняется. Транзакция при этом продолжает работать.
Необходимо пользоваться событиями IBDataset - OnPostError, OnEditError, OnDeleteError? Этого достаточно? А как определить конкретную причину ошибки? А для IBTransaction вообще ошибок быть не может? Или вообще нужно пользоваться IBEvents?Dimitry Sibiryakov писал(а):1) Ошибка, конечно, вернется. Компоненты обычно при этом бросают исключение. Его можно ловить и реагировать.
Я в этом деле абсолютный новичок и не пойму как обрабатывать исключения.
IBEvents - для отлова событий, которые ты сам себе посылаешь с сервера соответствующей командой. Пока не трогай этот компонент.Шмель писал(а):Или вообще нужно пользоваться IBEvents?
Это события для централизованной обработки соответствующих исключений. Используй их, это даже будет более правильным, чем я тебе предложил. С их помощью ты можешь повесить все датасеты на один обработчик соответствующего исключения.Шмель писал(а):Необходимо пользоваться событиями IBDataset - OnPostError, OnEditError, OnDeleteError?
Я ошибся. Могут быть. Например, при создании индекса. Сам запрос пройдет без ошибок. А вот при коммите, если таблицы используются, то создание индекса отменяется. Но сама транзакция не закрывается. Ты уже потом сам думаешь, отменять все или постить то что есть.Шмель писал(а):А для IBTransaction вообще ошибок быть не может?
Не ошибся, а отвечал в контексте DML, выполняющегся на execute, в отличие от DDL, выполняющегося на commit, а на execute только пишущего инфу для выполнения в системные таблицы. Если про это забыть и, например, выполнять DDL и DML на одних и тех же или связанных объектах в одной транзакции, то можно изрядно наломать дров в базе.Cybermax писал(а): Я ошибся. Могут быть. Например, при создании индекса. Сам запрос пройдет без ошибок. А вот при коммите, если таблицы используются, то создание индекса отменяется. Но сама транзакция не закрывается. Ты уже потом сам думаешь, отменять все или постить то что есть.
-
- Заслуженный разработчик
- Сообщения: 1436
- Зарегистрирован: 15 сен 2005, 09:05
Да ты що, Джолтый? (С) DML - в зависимости от wait-nowait, ессно, DDL - не знаю, ибо альтерить одну и ту же таблицу как-то не доводилось в два смычка Если насчёт object in use с ХП - на коммите. Причём на классике конфликт может выразиться просто в падении одного из процессовDimitry Sibiryakov писал(а):А, вот, например, конфликт изменений в двух транзакциях когда вылезет? Сразу или только по коммиту?
-
- Заслуженный разработчик
- Сообщения: 1436
- Зарегистрирован: 15 сен 2005, 09:05
Блин, а почему же у меня откуда-то засело в голове что при каком-то сочетании трансизоляций ошибка должна вылезти при попытке коммита?.. Где-то я на эти грабли наступал... У меня коммит обламывался, а после этого обламывался и дисконнект (транзакция оставалась активной) - пришлось проверять успешность коммита и при необходимости делать роллбэк. Возможно, при TPC... Нет, не помню.