![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Полтергейсты SQL Server или всё "намана"? [D7, MSSQL]
31512 © (2004-03-26 09:10:00)Дело было так ... Моя мечта попробовать создать трёхуровневое приложение для базы данных (SQL Server 2000), с некоторых пор начала обретать физическую форму. Для создания самоей БД на сервере я сначала использовал Access. Ну, чего проще? Сляпал БД, вызвыл "Мастер преобразования в формат SQL Server" и ... собственно больше ничего не требуется. Но потом мне надоело каждый раз лезть в Access, когда возникала необходимость создать БД заново. Тогда я написал SQL-скрипт, как говорится, "в раз и навсегда", внося по мере необходимости в него ихменения. А заставить SQL серевер выполнить SQL-скрипт не так уж сложно, да и быстрее это раз в 30.
Но вот какая фигня стала происходить. В случае создания БД Accessом, достаточно было выставить нужные флаги у DataSetProviderов для серверного приложения, чтобы в клиентском приложении при вызове метода TClientDataSet.ApplyUpdates(ErrorCount : integer) все изменения аккуратно принимались, в том числе происходили и корректные изменения в самой БД. При этом никаких дополнительных действий принимать не требуется, т.е. используются самые стандартные возможности DBшных компонентов. Однако, если БД создана посредством скипта, то ничего подобного не наблюдается. Вставить новую запись - без проблем, но на удаление и изменение получаю ошибку "Запись была изменена или занята другим пользователем" сообщением "Не удалось найти запись". И только создание бизнес-правила в методе TRemoteDataModule.DataSetProviderBeforeUpdateRecord
позволяет выполнять всё корректно. Почему же возникают, как говорят в Одессе, такие "две большие разницы"?
У меня: D7, SQL Server 2000, WinXP SP1 RUS, Office XP(with FrontPage), ADO (MDAC 2.7), MIDAS.
31512 (2004-03-29 11:31:00) [21]Всем спасибо! До следующих "полтергейстов" :).
Romkin (2004-03-26 21:20:00) [22]ДЫк понимать надоть :)) Я специально вставку в статье сделал, что да как. Провайдер управляет всем, надо только ему объяснить.
Кстати, отнюдь не факт, что надо именно WhereKeyOnly, это от логики зависит :)
Nikolay M. (2004-03-26 16:54:00) [23]
> Romkin © (26.03.04 16:45) [23]
> Nikolay M. Сразу надо посылать на rsdn ;)
Дык самому интересно потелепатировать :)
> а у DataSetProviderа UpdateMode := upWhereKeyOnly
А до этого какое значение было? Видимо, на мой пост [4] особого внимания не обратил?
Romkin (2004-03-26 16:45:00) [24]31512 © (26.03.04 16:33) [22] :))) Ты бы таки прочитал полностью вставку в статью.
"Запись изменена другим пользователем" выдается, когда в ответ на запрос на изменение, сформированный провайдером, сервер выдает, что никаких записей не изменено (есть такой статус).
Nikolay M. Сразу надо посылать на rsdn ;)
31512 (2004-03-26 16:33:00) [25]Теперь о решении проблемы.
Великий Romkin"полил свету на проблему эту, оказалось, что проблемы-то и нету"
У ключевых полей ADOQuery выставляем флаг pfInKey, а у DataSetProviderа UpdateMode := upWhereKeyOnly.
И всё работает.
Моё предположение таково:
Мастер Accessa тщательней конфигурирует поля, благодаря чему они корректно распознаются ADO и корректно передаются.
Возможно я заблуждаюсь.
31512 (2004-03-26 16:28:00) [26]Для Nikolay M.
Одна таблица - один ADOQuery. ADOQuery - тут один, поскольку работаем всего с единственной таблицей БД.
ADOQuery.Close - там лишний, в баню его. Затесался незнамо как.
ADOQuery.SQL.Text:='select * from ORGANISATION';
ADOQuery.Open;
просто обновляем. Согласен, можно и по другому.
Nikolay M. (2004-03-26 15:50:00) [27]ОООО....
Сразу 3 вопроса (больше лень писать):
1) У тебя что, везде используется один и тот же объект ADOQuery? И для выборки, и для удаления, и для непонятно зачем повторной выборки?
2) Зачем это?
> ADOQuery.ExecSQL;
> ADOQuery.Close;
3) И это?
> ADOQuery.SQL.Text:='select * from ORGANISATION';
> ADOQuery.Open;
31512 (2004-03-26 15:40:00) [28]Это бизнес-правило на удаление записей ...
procedure TRemoteDataModule.DataSetProviderBeforeUpdateRecord(
Sender: TObject; SourceDS: TDataSet; DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind; var Applied: Boolean);
var Delete_ID : string;
begin
if UpdateKind=ukDelete then
begin
ADOQuery.Open;
Delete_ID := DeltaDS['ID_ORGANISATION'];
ADOQuery.SQL.Text:='update ORGANISATION set DELETED=1 where ID_ORGANISATION = '+Delete_ID;
ADOQuery.ExecSQL;
ADOQuery.Close;
ADOQuery.SQL.Text:='select * from ORGANISATION';
ADOQuery.Open;
Applied := True;
end;
if UpdateKind=ukModify then
begin
?????
Applied := True;
end;
end;
Что можно написать для обновления? Вместо ?????
31512 (2004-03-26 15:33:00) [29]Интересно. Я сделал if i=0 then ADOQuery.Fields[i].ProviderFlags := [pfInKey, pfInUpdate]. И с начала болучил обычный банан через HandleReconcileError(DataSet, UpdateKind, E);
Потом я р\переноше тот же код в TRemoteDataModule.RemoteDataModuleCreate и теперь получаю бананы через обычный MessageBox... :smile:
Nikolay M. (2004-03-26 15:09:00) [30]Попробуй
if i=0 then ADOQuery.Fields[i].ProviderFlags := [pfInKey, pfInUpdate]
31512 (2004-03-26 15:05:00) [31]Наверное не там флаги выставляю.....
31512 (2004-03-26 15:01:00) [32]Выставляю флаги:
function TRemoteDataModule.DataSetProviderDataRequest(
Sender: TObject; Input: OleVariant): OleVariant;
var i : integer;
begin
ADOQuery.Close;
ADOQuery.SQL.Text:='select * from ORGANISATION';
ADOQuery.Open;
for i:=0 to ADOQuery.FieldCount - 1 do
begin
if i=0 then ADOQuery.Fields[i].ProviderFlags := [pfInKey] - это ключевое поле
else ADOQueryFields[i].ProviderFlags := [pfInUpdate];
end;
end;
Всё равно выходит банан...
31512 (2004-03-26 11:26:00) [33]Для Nikolay M.
Ага... Попробуем.
Nikolay M. (2004-03-26 11:11:00) [34]
> Можешь уточнить, что за флаги полей?
> TField.ProviderFlags.pfInKey - идентефикация с помощью первичного
> ключа БД ....
Для ключевый полей: pfInKey, для полей, которые будут изменяться: pfInUpdate.
31512 (2004-03-26 10:52:00) [35]Для Nikolay M.
Ты хочешь сказать, что после выполнения каждого запроса, я должен в получившемся DataSetе выставлять флаги полей? Можешь уточнить, что за флаги полей? Может мы про разные вещи говорим...
Nikolay M. (2004-03-26 10:48:00) [36]
> Для провайдера и в том и в другом случае выставлены одни
> и те же флаги:
Я имел ввиду флаги для полей.
> Может чего с бизнес-правилами порекомендуешь? Я имею ввиду
> обработчик TRemoteDataModule.DataSetProviderBeforeUpdateRecord
А что я тут могу порекомендовать?
31512 (2004-03-26 10:37:00) [37]Для Nikolay M.
Может чего с бизнес-правилами порекомендуешь? Я имею ввиду обработчик TRemoteDataModule.DataSetProviderBeforeUpdateRecord.
31512 (2004-03-26 10:34:00) [38]Для Nikolay M.
В том-то и дело, что с этого всё и начинается. Для провайдера и в том и в другом случае выставлены одни и те же флаги:
poFetchBlobsOnDemand = True
poFetchDetailsOnDemand = True
poIncFieldProp s= True
poCascadeDeletes = True
poCascadeUpdates = True
poAllowMultiRecordUpdates = True
poAutoRefresh = True
poAllowCommandText = True
poRetainServerOrder = True.
У остальных False.
Nikolay M. (2004-03-26 10:29:00) [39]Попробуй руками выставлять необходимые флаги провайдера. Помню, тоже как-то приходилось так делать, но не вспомню, почему.
31512 (2004-03-26 09:55:00) [40]Для Nikolay M.
Тогда не ясно, почему такая разница для БД созданной Accessом и скриптом, если флаги выставляются на клиенте. В том-то и фикус-пикус, что одна и та же программа ведёт себя по разному с абсолютно одинаковыми БД по структуре, но разными по "происхождению". Ну имена у этих баз данных разные. Делов - то строчку подключения в ADOConnection на серверном прилодении подправить.