Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > БД в Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 04.10.2008, 09:45   #11
Rik
Форумчанин
 
Аватар для Rik
 
Регистрация: 28.07.2007
Сообщений: 361
По умолчанию

Надо сделать так, чтобы при IBTable.Append на сервер ничего не уходило, у вас какой то косяк с компонентами. Когда вы делаете IBTable.Append на самом деле добавляется временная строка в локальном буфере на стороне клиента, в этот момент на сторону сервера ничего не передается. Когда вы делаете IBTable.Post, вот в этот момент должен уходить запрос INSERT с заполненными параметрами на сторону сервера, там в триггере обычно прописывают код, который смотрит, имется ли ID записи, если ID записи нет, т.е. если он на стороне клиента не сгенерирован, он генерится в триггере. Если есть триггер в котором прописана генерация ID, в любом случае, должен обеспечивать ID записи. И в любом случае, пока вы сами не вызовите IBTable.Post ошибки точно не должны валиться. Тут дело не в not null, не в триггерах и генераторах, смотрите настройки IBExpress на стороне клиента и ищите ошибку. Если есть триггер, он должен обеспечить ID записи в любом случае, возможно сервер ругается совсем даже не на поле ID записи, возможно есть другие поля, которые имеют свойство not null, и возможно у вас сразу после IBTable.Append сразу идет IBTable.Post, сохраняя пустую запись. На всякий случай уберите всякие там Prepare в компонентах.... Проверте, нет ли чего лишнего в событиях IBTable.beforeInsert, IBTable.OnNewRecord. Not null, триггер и генератор в вашем случае на 200% ни при чем.
ID записи можно сгенерить на стороне клиента. Выбросьте IBTable, используйте IBDataset, в нем можно указать генератор, тогда ID записи будет генериться на стороне клиента.

Последний раз редактировалось Rik; 04.10.2008 в 10:24.
Rik вне форума Ответить с цитированием
Старый 09.10.2008, 05:49   #12
Surgeon
Форумчанин
 
Регистрация: 04.10.2007
Сообщений: 106
По умолчанию

Цитата:
Сообщение от Rik Посмотреть сообщение
Надо сделать так, чтобы при IBTable.Append на сервер ничего не уходило, у вас какой то косяк с компонентами.
Маловероятно, что косяк.
Цитата:
Сообщение от Rik Посмотреть сообщение
Когда вы делаете IBTable.Append на самом деле добавляется временная строка в локальном буфере на стороне клиента, в этот момент на сторону сервера ничего не передается.
Вот этот момент я в рассуждениях пропускал.
Цитата:
Сообщение от Rik Посмотреть сообщение
Когда вы делаете IBTable.Post, вот в этот момент должен уходить запрос INSERT с заполненными параметрами на сторону
сервера,
Пост я делаю в конце цикла когда добавлены все импортируемые записи, а вылет происходил при добавлении первой же.
Цитата:
Сообщение от Rik Посмотреть сообщение
там в триггере обычно прописывают код, который смотрит, имется ли ID записи, если ID записи нет, т.е. если он на стороне клиента не сгенерирован, он генерится в триггере. Если есть триггер в котором прописана генерация ID, в любом случае, должен обеспечивать ID записи.
Триггер включен, он на BeforeInsert, значит ID генерится полюбому.
Цитата:
Сообщение от Rik Посмотреть сообщение
И в любом случае, пока вы сами не вызовите IBTable.Post ошибки точно не должны валиться. Тут дело не в not null, не в триггерах и генераторах, смотрите настройки IBExpress на стороне клиента и ищите ошибку. Если есть триггер, он должен обеспечить ID записи в любом случае, возможно сервер ругается совсем даже не на поле ID записи, возможно есть другие поля, которые имеют свойство not null, и возможно у вас сразу после IBTable.Append сразу идет IBTable.Post, сохраняя пустую запись.
Если не not null то можно добавлять запись у которое заполнено только одно поле - ID.
Цитата:
Сообщение от Rik Посмотреть сообщение
На всякий случай уберите всякие там Prepare в компонентах.... Проверте, нет ли чего лишнего в событиях IBTable.beforeInsert, IBTable.OnNewRecord. Not null, триггер и генератор в вашем случае на 200% ни при чем.
ID записи можно сгенерить на стороне клиента. Выбросьте IBTable, используйте IBDataset, в нем можно указать генератор, тогда ID записи будет генериться на стороне клиента.
Я вас понял почти.

Итак связка триггер+генератор дает уникальность.
===
Пользуюсь компонентами IB но сам сервер у меня не установлен даже, у меня FireBird., соответственно ни за какой IBExpress разговор не идет.
Все не так плохо, как вам кажется, на самом деле все гораздо хуже.
http://delphiworld.narod.ru/dw.html - 5000 статей!!! удобный поиск, оффлайн сборник, рекомендую всем
Surgeon вне форума Ответить с цитированием
Старый 09.10.2008, 06:14   #13
Rik
Форумчанин
 
Аватар для Rik
 
Регистрация: 28.07.2007
Сообщений: 361
По умолчанию

Цитата:
Пользуюсь компонентами IB но сам сервер у меня не установлен даже, у меня FireBird., соответственно ни за какой IBExpress разговор не идет.
FireBird и есть SQL сервер, как бы вы без него работали то... Компоненты IB раньше назывались IBExpress, я по привычке их так называю...

Цитата:
Пост я делаю в конце цикла когда добавлены все импортируемые записи, а вылет происходил при добавлении первой же.
Ох Ох... Не знаю плакать или смеяться, простите конечно. Может вы неправильно выразились. Post должен идти после каждой добавленной записи, после всех записей обычно идет подтверждение транзакции - Commit, Commit можно тоже при необходимости вызывать после каждой записи.
while not Table1.eof do
begin
//Добавляем строку в локальном буфере
IBTable.Append;
//...Заполняем поля...
For I := 1 to 20 do
begin
IBTAble.Fields[i].Value := Table1.Fields[i].Value;
end;
//Вот здесь вызываем пост и одна запись с заполненными полями уходит на сервер
IBTable.Post;
//Переходим к следующей записи
Table.Next;
end;
//Подтверждаем транзакцию
MyTransaction.Commit;

Последний раз редактировалось Rik; 09.10.2008 в 06:32.
Rik вне форума Ответить с цитированием
Старый 09.10.2008, 10:52   #14
Andrei
Форумчанин
 
Регистрация: 20.06.2007
Сообщений: 270
По умолчанию

Первоначальную проверку на Not Null выполняет не сервер БД, а локальный датасет. В вашем случае это IBTable. Он-то и формирует SQL команду INSERT для сервера БД в неявном виде. Кстати, проверку на уникальность полей и сортировку по индексу он перекладывает на сервер БД. Поэтому первоначальное значение ключевого поля может быть любым ненулевым, лишь бы соответствовало типу поля.

Как вы правильно заметили, уникальность поля обеспечивает триггер на BeforInsert сервера БД. Ему по барабану, какое значение для этого поля вы укажете в своей команде INSERT. Он все равно заменит его на своё. Я бы вообще исключил это поле из команды INSERT, но, так как вы пользуетесь компонентом IBTable - эта возможность вам не доступна.

Если я правильно понял, перед вами стоит задача механической перекачки данных из одной таблицы в другую.

Способ 1:
Вместо Append воспользуйтесь AppendRecord. Сформируйте полностью запись из данных исходной таблицы примерно так же, как вы делаете в своей программе, а вместо ключевого поля вставляйте любое ненулевое значение соответствующего типа. Только Post делать не надо. AppendRecord выполняет её автоматически.

Способ 2:
Делать так, как делаете вы, но отключить первоначальную проверку на Not Null в локальном датасете. Для этого нужно зайти в свойствах IBTable зайти в FieldDefs -> ваше поле -> Attributes и установить свойство faRequired в False. Это позволит вам добавлять пустые записи в локальный датасет без проблем, однако, перед тем, как выполнить Post обязательно нужно присвоить этому полю любое ненулевое значение соответствующего типа, иначе ругаться будет уже не локальный датасет, а сервер БД.

На мой взгляд первый способ корректнее.
-Кукушка, кукушка! Накукуй мне сто лет!
-А накукуй тебе столько?

(с) Библия. Вольный перевод с древнееврейского.

Последний раз редактировалось Andrei; 09.10.2008 в 10:57.
Andrei вне форума Ответить с цитированием
Старый 10.10.2008, 05:32   #15
Surgeon
Форумчанин
 
Регистрация: 04.10.2007
Сообщений: 106
По умолчанию

Цитата:
Сообщение от Rik Посмотреть сообщение
FireBird и есть SQL сервер, как бы вы без него работали то...

Цитата:
Сообщение от Rik Посмотреть сообщение
Ох Ох... Не знаю плакать или смеяться, простите конечно. Может вы неправильно выразились. Post должен идти после каждой добавленной записи, после всех записей обычно идет подтверждение транзакции - Commit, Commit можно тоже при необходимости вызывать после каждой записи.
Как оказалось - не так сказал как сделал. Хотя сначала не делал CommitRetaining - поэтому удивлялся почему измененения не видны сразу в БД. Пробовал пост и до и после Append. Refresh вызывал...
Поэтому и не уверен как сделал в последней версии:

Код:
 begin
 ADOTImportF7.Active:=true;
 IBTF7.Active:=true;
 SHowProgress.Max:=ADOTImportF7.RecordCount;
   for i:=1 to ADOTImportF7.RecordCount do
    begin
     IBTF7.Edit;
     ADOTImportF7.RecNo:=i;
     ShowProgress.Position:=i;
     IBTF7.Append;
     IBTF7.FieldByName('RRSUBMITDATE').Value:=Date;
     IBTF7.FieldByName('RRSUBJECT').Value:=IBTPredmTable.FieldValues['PREDMID'];
...
      for k:=4 to 10 do
        begin
         IBTF7.Fields[k+6].Value:=ADOTImportF7.Fields[k].Value;
        end;
     IBTF7.Post;
     Application.ProcessMessages;
    end;
  ADOTImportF7.Active:=false;
  IBTF7.refresh;
  DMDekanat.MainTransaction.CommitRetaining;
 end;

Цитата:
Сообщение от Andrei Посмотреть сообщение
Если я правильно понял, перед вами стоит задача механической перекачки данных из одной таблицы в другую.
Не стоит уже, меня сечас именно интересует вопрос а насколькоправильно делать так или иначе, и почему. У меня сейчас чисто академический интерес.

Цитата:
Сообщение от Andrei Посмотреть сообщение
На мой взгляд первый способ корректнее.
Вот это меня и интересует. Спасибо что ответили.
Все не так плохо, как вам кажется, на самом деле все гораздо хуже.
http://delphiworld.narod.ru/dw.html - 5000 статей!!! удобный поиск, оффлайн сборник, рекомендую всем
Surgeon вне форума Ответить с цитированием
Старый 10.10.2008, 14:55   #16
Rik
Форумчанин
 
Аватар для Rik
 
Регистрация: 28.07.2007
Сообщений: 361
По умолчанию

Цитата:
for i:=1 to ADOTImportF7.RecordCount do
begin


IBTF7.Edit; //Эта строка лишняя. Из за неё ошибка может быть


ADOTImportF7.RecNo:=i;
ShowProgress.Position:=i;
IBTF7.Append;
Лишняя строка у вас есть...
Rik вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Ошибка при использовании OlePropertyGet("Documents").OleProcedure("Add") в C++ Builder AleksP C++ Builder 7 11.04.2009 13:06
если пользователь наберет какой-то другой символ не "y" или "n" и нажмет enter, программа проигнорирует skobets Общие вопросы C/C++ 2 03.06.2008 06:51
Excel файл открывается не "до конца" (странички "не показываются" только серое поле) Dorvir Microsoft Office Excel 2 28.03.2008 10:03
Создаю диаграмму "Bar". Подскажите как убрать растояние между "столбами" MAcK Компоненты Delphi 11 24.10.2007 10:49
На чем пишутся стратегии типа "Казаков" и "Эпохи империи" Tayfun Свободное общение 3 26.06.2007 20:27