Форум: "Базы";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.21;
Скачать: [xml.tar.bz2];




Вниз

Delete from master-detail via stored procedure 


Гоша   (2001-12-13 19:00) [0]

Просто беда...
BDE, TDataBase, TQueries, TStoredProcedure, CachedUpdates...
2 (или более) TQuery связаны как master-detail (связаны "вручную" - не через DataSource, ибо, как выяснилось, так не прокатит! - господи, как я люблю BORLAND и его детище!)
Ладно, навтыкал обработчиков, чтобы переопредлять параметры для detail и переоткрывать его (их), когда надо мне, а не ему.
Теперь встал вопрос об удалении всей грозди. Слепил sp на сервере, к-рая по PK master-записи удаляет все веточки и ее саму(опять-же, а ну попробуй сделать это на клиенте: пиши циклы WHILE NOT EOF ! Я уже выражал свое мнение относительно "удобства" DELPHI для приложений БД - ну нету у нее "встроенного SQL", чтобы работать с наборами данных по-нормальному!!).
А теперь вопрос: процедура отрабатывает, на сервере записи удаляются, мне приходит result, что, типа, все OK, а на любое телодвижение с набором данных после этого получаю сообщение:"Connection is in use by another statement" !
Офигев от этого, делаю совершенно простенький пример (ничего лишнего на форме, только 2 Query, master-detail - правда, по-простому - через DataSource) и аналогичную sp.
Запускаю - работает ! И ничем мой connection не занимает.
Ну, думаю, блин... И добавляю пару строчек после StoredProc1.ExecProc:
Query1.Delete; //чтобы визуально удалить запись в моем наборе
Query1.CommitUpdates; //очистить кэш
И получаю на команду Delete ответ: сбой при обращении к странице памяти в модуле SQLMSS32.DLL !
И тут я шизею...
М.б. кто-нибудь подскажет, какой учебник тут читать надо ?



Mick   (2001-12-13 19:03) [1]

Учебник по принципам построения клиент-серверных приложений



Гоша   (2001-12-13 19:05) [2]

>Mick: Ну ты сказал !



drpass   (2001-12-13 23:07) [3]

Я, правда, не с MS SQL работаю, но... нафиг делать поддержку целостности данных в клиентском приложении? Почему бы не настроить ее на самой базе данных? Ведь есть в SQL Server триггеры или какой-то их аналог, там, скажеи, автоматический запуск хранимой процедуры при удалении записей



Гоша   (2001-12-14 10:13) [4]

>drpass: Я, конечно, понимаю, что с триггерами сподручнее, чем самому.
Но представьте ситуацию, когда изменять структуру БД невозможно (добавлять новые объекты типа sp или view можно, а менять существующие нельзя), так ведь бывает, правда ?
Но дело не в этом! Меня бесит непонимание того, что происходит!
Сначала я никак не мог понять, почему не работает master-detail через DataSource (во всех пособиях мило объясняется именно этот вариант и нигде ни слова о том, что так не пройдет с CachedUpdates). Спасибо, добрые люди подтвердили, что, действительно придется связывать самому, ручками через код.
Теперь вдруг этот несчастный connection, к-рый вдруг оказывается занят каким-то another statement после выполнения sp. У меня крепнет чувство, что чего-то глубоко здесь недопонимаю... А м.б. все проще гораздо?
Подскажите хоть, в каком направлении искать, откуда ноги растут у этой дряни.



Tonie   (2001-12-14 13:45) [5]

> drpass ©
MSSQL до 2000 версии имеет триггеры без деления на Befor After, не поддерживает каскадного удаления, а проверка referential integrity происходит раньше удаления записи, так что приходится действительно пользоваться легкими извратами.
> Гоша © собственно проблем со стандартным Master - Detail особенно не припоминаю, при подробном описании проблемы и знаниии версии MSSQL было бы проще помочь



Гоша   (2001-12-14 13:55) [6]

>Tonie: Дружище, помоги!
А проблему, собственно я уже описал... (MS SQL 2000 но не в этом дело, дело в том, что я не понимаю, как работает в данном случае DELPHI и что делать...)



Kapusto   (2001-12-14 14:06) [7]

Ну если MSSQL2000, тогда рыть в сторону referential constraints, on delete cascade



Гоша   (2001-12-14 14:47) [8]

Блин, да устал уже говорить, что не могу МЕНЯТЬ структуру существующих объектов в БД ! Это не мои объекты.
Ди и не хочу ! Хорошо, переформулирую вопрос: Если RI не обеспечивается средствами сервера, то что же выходит - в DELPHI нельзя ее обеспечить програмным способом ?! Причем, по большому счету - какая разница, идет ли CASCADE DELETE через, напр., триггер на master-таблице, или через вызов sp?
Делается-то ведь одно и то же (и делается на сервере хорошо)! Проблема-то совсем в другом (8-:O)!!!



Tonie   (2001-12-14 15:06) [9]

>Гоша ©
Немного кода не помешало бы, и какие проблемы со стандартной реализацией Master-Detail



Гоша   (2001-12-14 15:50) [10]

>Tonie: Ты, правда, хочешь помочь?
Тогда вопрос: приходилось ли тебе реализовывать master-detail через TQuery и CachedUpdates? (заметь, ни слова про тип сервера). Если да, то готов поспорить о том, что вряд-ли ты это сделашь стандартным способом...
Если нет, то попробуй...



Tonie   (2001-12-14 18:28) [11]

> Гоша ©
Собственно опять же непонятно:
1. Как организованна связь между запросами
2. Как идет запись в DB, UpdateSQL ??, отдельные запросы ....
3. Какие поля используются для связи, автоинкрементные или задаются с клиента??
4. Код обработки транзакции ...
....
Кстати не обязательно sp писать, можно в запросе на удаление записи в Master DataSet предварительно удалить соответствующие записи в Detail DataSet, прекрасно функционирует



Гоша   (2001-12-17 10:50) [12]

>Tonie:
Ну давай по кусочкам:
1. Связь между запросами прописана кодом на (напр.) событие AfterScroll mast-qry:
- det-qry.Close;
- det-qry.ParamByName("field_i").AsInteger:=mast-qry.FieldByName("field_i").Value;
- det-qry.Open;
2. Запись в БД идет через UpdateSQL (Database.ApplyUpdates([mast-qry,det-qry]);) кроме операции удаления (она выполняется посредством StoredProc.ExecProc;)
3. Про поля для связи см. п.1
4. "Код обработки транзакции ..." ? - не понял, что ты имеешь в виду.
Если запись ИЗМЕНЕНИЙ через ApplyUpdates, то полагаюсь на механизм DataBase.ApplyUpdates, если же запись УДАЛЕНИЯ, то транзакция объявляется в stored proc на сервере.
PS: насчет необязательности писания sp: IMHO код будет гораздо кучерявее:
1) удалить все записи в det-qry (а их неск-ко) и master-запись
2) а потом мудрить с кодом для транзакции подтверждения всех этих изменений в БД (последовательно вызывать ApplyUpdates для всех det-qry, и, если все пройдет, то делать ApplyUpdates для mast-qry)
3) обрабатывая все неожиданности... Стоит оно того ?
Что-нибудь еще ?



Гоша   (2001-12-17 13:54) [13]

Кажись, чуть-чуть разобрался... (Оно меня с ума сведет !)

Фича с "Connection is in use by another statement" исчезла после того, как я убрал StoredProc1.Prepare (и соотв. Unprepare) из событий DataBase1.AfterConnect (соотв. BeforeDisconnect).

Вот ведь блин ! Не надо, стало быть, читать всяческие умные советы в Help"ах насчет того, что-де, лучше это сделать самому, если-де предполагается исп-ть компонент неск-ко раз.

Почему-то в случае предварительного и явного (одноразового) Prepare выполнение StoredProc транслируется на сервер так (из SQL Monitor):

48 12:07:27 SQL Stmt: MSSQL - Close
49 12:07:27 SQL Prepare: MSSQL - a_del_zoom_loc_sp :1, :2,
50 12:07:27 SQL Data In: MSSQL - Param = 1, Name = , Type = fldINT32, Precision = 0, Scale = 0, Data = 26100
51 12:07:27 SQL Data In: MSSQL - Param = 2, Name = , Type = fldINT32, Precision = 0, Scale = 0, Data = 600
52 12:07:27 SQL Execute: MSSQL - a_del_zoom_loc_sp :1, :2,
и все !

А вот если не забивать себе голову ерундой и положиться на Борланда (дедушка умный! он сам сообразит насчет и Prepare и Unprepare), то тогда будет так:

48 11:52:20 SQL Prepare: MSSQL - a_del_zoom_loc_sp :1, :2,
49 11:52:20 SQL Data In: MSSQL - Param = 1, Name = , Type = fldINT32, Precision = 0, Scale = 0, Data = 26100
50 11:52:20 SQL Data In: MSSQL - Param = 2, Name = , Type = fldINT32, Precision = 0, Scale = 0, Data = 600
51 11:52:20 SQL Execute: MSSQL - a_del_zoom_loc_sp :1, :2,
52 11:52:20 SQL Stmt: MSSQL - Close //Вот этого и не хватало!
53 11:52:20 SQL Stmt: MSSQL - Close //Вот Connection и оставался in use!

Объясните, кто понимает, чего старичок (я) не сообразил.

А вот на закуску:
Я (наивный!) полагал, что если запись на сервере благополучно удалена, то визульно удалить ее в моем наборе не просто, а очень просто:

Query.Delete; //запишем в кэш как удаленную
Query.CommitUpdates; //очистим кэш

А вот фиг вам!!!
Знаете, что транслируется на сервер по команде CommitUpdates ?
Попытка выполнить команду DELETE...FROM...WHERE...!
Я не могу это откомментировать...

PS:Конечно, понимаю, что верный способ отобразить изменения через Close, Open. Но опять же, зачем огород городить...



Tonie   (2001-12-17 14:40) [14]

1. Если непременно нужно через sp стирать и UpdateSql использовать то тогда лучше вызов sp сделать прямо из UpdateSql : exec YourSp :Param1 :Param2, тогда на уровне клиента вообще про нее неизвестно и все с помощью UpdateSql проходит.

2. Я в испуге набросал попробовал сам (может я чего забыл) короче две таблицы : MAST - DTL, связь ID - ID_MAST, два запроса связаны через
DataSource, для мастера UpdateSql.DeteteSql =

Delete from Dtl where MAST_ID = :OLD_ID
Delete from Mast where ID = :OLD_ID


Запись в базу


begin
try
db1.StartTransaction;

quMaster.ApplyUpdates;
quDetail.ApplyUpdates;

db1.Commit;
except
db1.Rollback;
raise
end;

quMaster.CommitUpdates;
quDetail.CommitUpdates;
end


P.S. это конечно модель, но работает, т.е. в чем основная проблема я так и не понял



Гоша   (2001-12-17 17:32) [15]

>Tonie:
Что касается твоего MAST-DTL и записи в базу: это классический пример, с к-рого собственно и начался весь геморрой. Ты действительно убеждался в том, что он работает в случае:

а) добавления master-записи, detail-записей а потом их всех скидывания в БД через твой фрагмент кода.

б) и даже проще: в уже имеющейся (считанной из БД) комбинации внести изменения в detail-набор а потом попытаться что-то отредактировать в master-записи (просто в локальном (кэшируемом) варианте, без передачи изменений на сервер) ?

Я столкнулся с тем, что это невозможно: при изменении статуса master-записи (dsBrowse->dsEdit или DsInsert->dsBrowse) detail-набор переоткрывается автоматически и все твои незафиксированные изменения в нем херит !!!

Буду удивлен, услышав, что у тебя ничего подобного не происходит (мне неск-ко человек подтвердили, что так и должно быть...)

Но повторюсь: Собственно проблему с вызовом sp я решил (вернее, случайно наткнулся на способ избежать ошибки) и остались (риторические?) вопросы касательно поведения BDE.
Ну не вижу я в нем здравого смысла :(



Mick   (2001-12-17 17:47) [16]

Если честно, то использование на клиенте конструкций Master_Detail при работе с SQL сервером это все же не совсем клиент-серверный подход (хоть и работает)
Это и многое другое сводит на нет все преимущества двузвенки.



Гоша   (2001-12-17 18:06) [17]

>Mick: Вот-те раз! А почему же master-detail это не наш метод для client-server ? Потому что много записей из master-таблицы выбирает ? А если всего несколько ? А если всего одну ?
Я даже больше скажу: мне удивительно такое индифферентное отношение практически всех здесь присутствующих к теме. Такое ощущение, что никто форм на master-detail не пишет. А по мне так не может быть сколько-нибудь значащего приложения для БД без таких форм...
Вот.



Mick   (2001-12-17 18:20) [18]

Понимаете, Гоша, я не говорил что это неработоспособно.
Но когда что-то пишется и тестируется на одной машине и на сотне другой записей и одним пользователем это одно.
А когда приложение начинает работать в реальном мире (нормальное количество пользователей, нормальные объемы данных, есть каналы 128 кбит) то это совсем другое.



Гоша   (2001-12-17 18:26) [19]

>Mick:Понимаете, Mick, я тоже не говорил, что "это работоспособно а все остальное нет". Я всего лишь удивился Вашим словам:

"использование на клиенте конструкций Master_Detail при работе с SQL сервером это все же не совсем клиент-серверный подход".

Не могли бы Вы эту фразу расшифровать ?



Mick   (2001-12-17 18:33) [20]

Пожалуйста, но это конечно только мое мнение:
Если пользователь на форме последовательно жмет кнопки Up/Down не выходя за пределы уже зафетченных с сервера записей, а на сервер продолжают улетать запросы, для отображения Detail секции это плохо.



Гоша   (2001-12-17 18:38) [21]

>Mick: Ну же, еще одной фразы не хватает: а как же лучше ?
PS: А если выходит "за пределы уже зафетченных с сервера записей" (напр., выбирает с сервера новую-одну! master-запись) - то тогда хорошо, тогда можно использовать master-detail ?!



Mick   (2001-12-17 18:47) [22]

Смысл на самом деле простой, и ясен ребенку:
Не тянуть с сервера ничего без необходимости.
Хочет юзер посмотреть записи связанные с основной - открыть ему отдельную форму. Как вариант - сделать объединение на сервере этих наборов (это уже НАМНОГО лучше простого M/D).



Гоша   (2001-12-17 18:57) [23]

>Mick: Я все никак не возьму в толк: "сделать объединение на сервере этих наборов (это уже НАМНОГО лучше простого M/D)" - да чем лучше-то? Какое-такое объединение ты сделаешь для счета-фактуры со строками, для человека с детьми (несть числа примерам).
"Хочет юзер посмотреть записи связанные с основной - открыть ему отдельную форму" - пользователи "тащатся" от такого интерфейса.
Все, не могу больше. Что, в самом деле все считают, что формы master-detail не нужны ? (Я имею в виду формы для разумного ввода/редактирования, ест-но)



Mick   (2001-12-17 19:08) [24]

Видимо мы про разное говорим, но все же.
* Чем лучше объединение на сервере? *
тем, что на клиента detail-записи будут фетчиться ОДИН раз. Это не самое оптимальное решение объединить одну мастер - запись со всеми детайл - записями(как красиво это отобразить на клиенте - это другой вопрос).
Клиент-сервер был придуман для того, чтобы минимизировать трафик между хостом, на котором лежат данные и клиентом, а не для того, чтобы пользователи тащились от интерфейсов.
Именно это я и имел ввиду, говоря что Master/Detail - не клиент серверный подход.
Про пользовательский интерфейс речи не было и нет.



Гоша   (2001-12-18 10:35) [25]

>Mick: Ладно, давай завязывать. Я так понимаю, что каждый остался при своем мнении, и пусть каждый реализует клиентский интерфейс и способ обмена данными с сервером как ему (и клиентам) удобнее (и разумнее). Это, в конце концов, тема для абстактной дискуссии.
А по простому вопросу, к-рый я привел выше, нет никаких комментариев? Я имею в виду поведение оператора Query.CommitUpdates для визуального удаления записи в наборе данных на клиенте после того, как она была удалена на сервере.
Да и Tonie что-то замолчал...




Форум: "Базы";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.21;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.8 MB
Время: 0.051 c
4-66401           qwertysdffsfsdfa      2001-11-22 01:19  2002.01.21  
Как читать буфер клавиатуры?


14-66349          Seeree                2001-11-23 14:33  2002.01.21  
Промышленное и заказное программирование


6-66327           Юра                   2001-10-29 13:18  2002.01.21  
О TIdMappedPortTCP


1-66292           SlavaG                2002-01-01 20:02  2002.01.21  
Тип переменной


1-66252           Gol2000               2002-01-02 08:43  2002.01.21  
Как в TRichEdit у отдельных строк поменять цвет фона (цвет бумаги) ?