Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: IBDataSet в Delphi  (Прочитано 13515 раз)
0 Пользователей и 1 Гость смотрят эту тему.
NeferSky
Постоялец

ru
Offline Offline
Бессмертный


« : 18-06-2015 06:50 » new

Доброго времени суток.
Разъясните мне кто-нибудь, пожалуйста, как именно обращаться с параметрами в IBDataSet.
Тут: http://www.ibase.ru/devinfo/ibx.htm русским по белому написано, что
Цитата
Вместо запросов в InsertSQL/UpdateSQL/DeleteSQL ( ... ) можно указывать вызов хранимых процедур.
Именно так я и хочу делать.

Суть вопроса:
IDE - Delphi7. Есть этот самый датасет dsShop. У него есть InsertSQL:
Код:
execute procedure shop_ins(:shop_num, :org_name, :city, :address, :merchant)

Сохраненка, которую он вызывает:
Код:
create or alter procedure SHOP_INS (
    SHOP_NUM type of column SHOP.SHOP_NUM,
    ORG_NAME type of column SHOP.ORG_NAME,
    CITY type of column SHOP.CITY,
    ADDRESS type of column SHOP.ADDRESS,
    MERCHANT type of column SHOP.MERCHANT)
as
begin
  insert into shop (
    id,
    shop_num,
    org_name,
    city,
    address,
    merchant,
    active_flag)
  values (
    gen_id(shop_id, 1),
    :shop_num,
    :org_name,
    :city,
    :address,
    :merchant,
    1);
end^

Как я это делаю сейчас:
Код:
with dsShop do
  begin
    Open;
    Insert;
    FieldByName('shop_num').AsString := frmShopEdit.edtShopNum.Text;
    FieldByName('org_name').AsString := frmShopEdit.edtOrgName.Text;
    FieldByName('city').AsString := frmShopEdit.edtCity.Text;
    FieldByName('address').AsString := frmShopEdit.edtAddress.Text;
    FieldByName('merchant').AsInteger := StrToInt(frmShopEdit.edtMerchant.Text);
    Post;
    Close;
  end;

Но, насколько я понимаю, Insert/Post - это некая "прямая" вставка, в обход сохраненки. Или нет? Исходя из статьи на ibase.ru, видимо, надо делать так:
Код:
with dsShop do
  begin
    Open;
    Prepare;
    ParamByName('shop_num').AsString := frmShopEdit.edtShopNum.Text;
    ParamByName('org_name').AsString := frmShopEdit.edtOrgName.Text;
    ParamByName('city').AsString := frmShopEdit.edtCity.Text;
    ParamByName('address').AsString := frmShopEdit.edtAddress.Text;
    ParamByName('merchant').AsInteger := StrToInt(frmShopEdit.edtMerchant.Text);
    Insert;
    Close;
  end;
но в ответ получаю, что Field "shop_num" not found.

Так как, все-таки, надо передавать параметры в сохраненку?
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #1 : 18-06-2015 07:38 » 

Цитата
Но, насколько я понимаю, Insert/Post - это некая "прямая" вставка, в обход сохраненки. Или нет?

нет. если указан InsertSQL, то он и будет вызываться. и в него будут попадать значения, которые вы передаете в поля (не в параметры) в режиме dsInsert/dsEdit.

т.е. должен нормально работать ваш текущий вариант, и он должен вызывать сохраненку сам.

з.ы. и не заморачивайтесь с Prepare, для статических запросов он вызовется автоматически, да и смысл он имеет только в том случае, если происходит многократный вызов одного и того же параметризованного запроса или если в рантайм надо, например, получить план выполнения запроса без отправки самого запроса на сервер.
« Последнее редактирование: 18-06-2015 07:41 от x77 » Записан

NeferSky
Постоялец

ru
Offline Offline
Бессмертный


« Ответ #2 : 18-06-2015 07:55 » 

Гм... А для чего же тогда используются параметры? Только для методов типа ExecQuery?
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #3 : 18-06-2015 08:07 » 

параметры используются не только в IBDataset. и нужны они для обращения к параметрам, а в вашем случае вам надо обращаться к полю, т.к. IBDataset - это шняга, работающая с двунаправленным набором данных. преобразования значений полей (по сути - буфера) в параметры для вызова нижележащих процедур датасет будет делать сам.
Записан

NeferSky
Постоялец

ru
Offline Offline
Бессмертный


« Ответ #4 : 18-06-2015 10:24 » 

Что-то я все равно не могу состыковать вызов... Аналогичный датасет dsKKM.
InsertSQL:
Код:
execute procedure kkm_ins(:shop_name, :kkm_num, :description)

Сохраненка:
Код:
create or alter procedure KKM_INS (
    SHOP_NAME varchar(50),
    KKM_NUM type of column KKM.KKM_NUM,
    DESCRIPTION type of column KKM.DESCRIPTION)
as
begin
  insert into kkm(
    id,
    shop_id,
    kkm_num,
    description,
    active_flag)
  values (
    gen_id(kkm_id, 1),
    (select s.id from shop s
     where s.shop_num = :shop_name),
    :kkm_num,
    :description,
    1);
end^

Вызов:
Код:
with dsKKM do
  begin
    Open;
    Insert;
    FieldByName('shop_name').AsString := frmKKMEdit.cbShopNum.Text;
    FieldByName('kkm_num').AsInteger := StrToInt(frmKKMEdit.edtKKMNum.Text);
    FieldByName('description').AsString := frmKKMEdit.memDescription.Text;
    Post;
    Close;
  end;

Результат:
dsKKM: Field 'shop_name' not found

Если датасет работает с полями - это значит, что в сохраненку ничего постороннего (не соответствующего набору полей) пихать нельзя?
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #5 : 18-06-2015 10:38 » 

а в SelectSQL что?
Записан

x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #6 : 18-06-2015 10:40 » 

просто чтобы параметры обрабатывались автоматически, их имена должны совпадать с именами столбцов таблицы. а для этого их надо сначала получить.
Записан

NeferSky
Постоялец

ru
Offline Offline
Бессмертный


« Ответ #7 : 18-06-2015 11:02 » 

SelectSQL:
Код:
select * from kkm_sel

Сохраненка:
Код:
create or alter procedure KKM_SEL
returns (
    ID type of column KKM.ID,
    SHOP_ID type of column KKM.SHOP_ID,
    KKM_NUM type of column KKM.KKM_NUM,
    DESCRIPTION type of column KKM.DESCRIPTION,
    ACTIVE_FLAG type of column KKM.ACTIVE_FLAG)
as
begin
  for select id,
             shop_id,
             kkm_num,
             description,
             active_flag
      from kkm
      into :id,
           :shop_id,
           :kkm_num,
           :description,
           :active_flag
  do
  begin
    suspend;
  end
end^

Цитата
их имена должны совпадать с именами столбцов таблицы
Наверное, это и будет ответом на тему...
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #8 : 18-06-2015 11:04 » 

попробуйте, не получится - будем копать дальше.
Записан

NeferSky
Постоялец

ru
Offline Offline
Бессмертный


« Ответ #9 : 18-06-2015 20:12 » 

Попробовал, конечно, поле попереименовывать, но делу это не помогло. Похоже, лучшим решением будет дергать сохраненку IBSQL'ем с параметрами, а датасет использовать только для просмотра. У датасета все запросы - те же IBSQL, поэтому и хотелось завести все одним компонентом. Отпишусь о результатах.
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #10 : 18-06-2015 21:05 » 

решайте задачу поэтапно. задайте SelectSQL, проверьте, что все работает, задайте InsertSQL, отладьте, потом - UpdateSQL. потом заверните их в процедуру.

судя по коду выше, вы пытаетесь вставлять запись, передавая ей код справочника магазинов. этот код вы получаете по имени, которое передаете параметром.

если я правильно понял, то в вашем случае имя магазина - это именно параметр, и задаваться он должен через ParamByName,а значения для вставки непосредствено в таблицу - через FieldByName.

ругань происходит потому, что селект отрабатывает только по таблице с ККМ-ами, shop_name там нет. поэтоум также можно попробовать переписать селект, подтащив по джойну название магазина из справочника.

но сами по себе все эти телодвижения мне кажутся лишними, и если вы сформулируете задачу, то наверное можно будет посоветовать что-то по-существу.
Записан

NeferSky
Постоялец

ru
Offline Offline
Бессмертный


« Ответ #11 : 22-06-2015 07:12 » 

В общем, исправил много недочетов в коде.
1) В БД выкинул использование доменов. (Где-то в документации по InterBase/FireBird указывалось, что домен можно редактировать, и при этом изменения коснутся всех полей и переменных, которым присвоен тип этого домена. Ни разу не получилось так сделать, только ограничения лишние накладывали)
Код:
create or alter procedure KKM_INS (
    ID integer,
    SHOP_ID integer,
    KKM_NUM bigint,
    DESCRIPTION varchar(255),
    ACTIVE_FLAG smallint)
as
begin
  insert into kkm(
    id,
    shop_id,
    kkm_num,
    description,
    active_flag)
  values (
    :id,
    :shop_id,
    :kkm_num,
    :description,
    :active_flag);
end^

2) В код Delphi в блоки Insert/Post Edit/Post включил все поля таблиц, с которыми работают датасеты. Соответственно, пришлось получать ID'шники из программы, и добавлять их в блоки, а не просто в БД их генерировать и присваивать. То же самое касается значений "по умолчанию".
С самого начала я не добавлял в параметры сохраненки абсолютно все поля. Для инсерта, например, значения по умолчанию и ID не указывал.

frmKKMEdit:
Код:
// Get shop param by name
with frmMain.sqlSber do
  begin
    SQL.Text := 'select * from get_shop_by_name(:shop_name)';
    ParamByName('shop_name').AsString := cbShopName.Text;       <- Находим ID того, что выбрал пользователь
    ExecQuery;
  end;
ShopID := frmMain.sqlSber.Fields[0].AsInteger;
frmMain.sqlSber.Close;

frmMain:
Код:
// Get new ID
with sqlSber do
  begin
    SQL.Text := 'select * from get_kkm_gen';
    ExecQuery;
  end;
KKMID := sqlSber.Fields[0].AsInteger;
sqlSber.Close;

// Insert
with dsKKM do
  begin
    Open;
    Insert;
    FieldByName('id').AsInteger := KKMID;
    FieldByName('shop_id').AsInteger := frmKKMEdit.ShopID;
    FieldByName('kkm_num').AsInteger := StrToInt(frmKKMEdit.edtKKMNum.Text);
    FieldByName('description').AsString := frmKKMEdit.memDescription.Text;
    FieldByName('active_flag').AsInteger := Integer(frmKKMEdit.cbActive.Checked);
    Post;
    Close;
  end;

3) Также пришлось получать в программе id-значения "выбираемых" полей из связанных таблиц.(Например, id значения, выбранного в комбобоксе). Можно, конечно, и массивы сюда прикрутить, типа локального кэша "id-value" таблицы, из которой заполняется комбобокс, но... излишество, имхо.
Сначала я пытался просто передавать значение в сохраненку, чтобы БД сама находила нужный ID.
Код:
execute procedure kkm_ins(:id, :shop_id, :kkm_num, :description, :active_flag)

Вот... С исправлением всего этого работает, тема закрыта. X77 благодарю за объяснение, советы и подсказки.

зы: После работы над этим проектом сделаю программу-демку, в которой все-таки попробую еще раз создать сохраненку инсерта с какими попало параметрами, и вызвать ее Edit/Post'ом Ага А то аж за живое задело - "а я хочу так!" Отлично
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #12 : 22-06-2015 07:19 » 

посмотрите на FIBPlus. там почти такой же набор компонентов, как в IBX, но при этом они умеют делать львиную часть рутинной работы. например, каждому датасету можно сразу указать, какое поле является ключевым и значением какого генератора заполняется, и многое другое.
Записан

NeferSky
Постоялец

ru
Offline Offline
Бессмертный


« Ответ #13 : 22-06-2015 07:26 » 

датасету можно сразу указать, какое поле является ключевым и значением какого генератора заполняется
IBX тоже так умеют) Спасибо за информацию, попробую. Однако, всегда стараюсь обходиться минимумом сторонних компонент, чтобы не расслабляться)
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines