Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2005.10.30;
Скачать: [xml.tar.bz2];

Вниз

Внешние ключи в контекст транзации.   Найти похожие ветки 

 
Девушка ©   (2005-09-18 23:03) [0]

Хочу в одной транзации добавить сначала добавить запись в родительскую таблицу (справочник), потом, без commit-а добавить запись в дочернюю таблицу в которой в связанном посредством внешнего ключа поле ссылается на еще не подтвержденную родительскую запись.
Выдается ошибка Foreign Key.
Транзакция настроена на ReadCommited.
Добавление записей происходит из DBGridEH, а справочники прописаны как LookUp-поля.

Как добавить запись?

Пример:
Есть таблица товаров и таблица приходов.
1. Стартанули транзакцию.
2. Добавили новый товар "Конфеты".
3. Добавили новый приход с товаром "Конфеты" (здесь возникает ошибка)
4. Либо подтвердили, либо откатили всю транзацию.


 
Desdechado ©   (2005-09-18 23:04) [1]

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


 
Девушка ©   (2005-09-18 23:11) [2]


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

Код получен. При трассировке в поле датасета дочерней таблице он виден и выбирается правильно.


 
Девушка ©   (2005-09-18 23:12) [3]

Код - в смысле, id-к


 
Ильш ©   (2005-09-19 06:11) [4]

в поле датасета виден
а на серваке его еще нет т.к. транзакция еще открыта


 
Ярослав   (2005-09-19 07:41) [5]

На серваке он есть, даже если транзакция не поттверждена!
Обе таблици, главная и подчиненная, должны использовать одну транзакцию


 
Johnmen ©   (2005-09-19 09:29) [6]

>посредством внешнего ключа поле ссылается на еще не подтвержденную родительскую запись.

Это (подтвержденная или нет) не имеет значения.
Ошибка - неверный ссылочный ключ при новом приходе. Другого быть не может.


 
Sergey13 ©   (2005-09-19 09:29) [7]

2Девушка ©   (18.09.05 23:03)
Как то у тебя все неправильно. 8-)
1.Если где то между 2 и 4 пунктами узер уйдет чай пить то транзакция будет висеть неограниченно долго. А она и так у тебя очень долгая.
2.Получать ИДшник родителя можно (и лучше) ДО вставки.
3.Лукап поля на здоровые справочники (а справочник товаров наверное немаленький) не есть хорошо, ИМХО.


 
msguns ©   (2005-09-19 10:14) [8]

Чтоб не было ситуации, описанной в [7] (долгая пишущая транзакция), надо разделять чтение и запись. Т.е. запись в справочник и добавление к нему в дочернюю таблицу данных о движении (приходе) должны выполнять в отдельной записывающей транзакции.
Делается это так:
1. На клиенте получаем обе записи (мастер и детал, деталов может быть несколько, например, если работаем через стрингрид или CDS)
2. Стартуем на сервере новую пишущую транзакцию
3. Определяем новый ID товара, "дернув" соотв. генератор
4. Записываем в справочник, используя явно полученный ID (п.3)
5. Записываем в детал, используя в качестве ключа связки тот же ID (п.3)
6. Подтверждаем транзакцию
7. Переоткрываем основные НД и заполняем (если есть) визуализирующие контролы (стрингрид, CDS,..)
8. Позиционируем осн. таблицу на ID (п.3), активируя таким образом только что добавленный товар.

ЗЫ. Из сабжа сделал вывод о том, что БД учета товаров построена по-любительски, без отражения в ней реальных объектов-документов.

ЗЫ2. Нельзя жестко связывать добавление в справочники с добавлением в БД оперативной информации. Можно серьезно оконфузиться ;)))


 
ANB ©   (2005-09-19 10:21) [9]

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

Другой вопрос, если ты ведешь учет остатков и вот тогда изменения в таблице остатков должны согласовываться с добавлением в таблицу проводок и/или строк документов. Как это сделать - написал msguns.


 
Девушка ©   (2005-09-19 11:17) [10]

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

> Обе таблици, главная и подчиненная, должны использовать
> одну транзакцию

Так оно и есть. ReadCommeted


> msguns ©   (19.09.05 10:14) [8]

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


 
Sergey13 ©   (2005-09-19 11:20) [11]

2[10] Девушка ©   (19.09.05 11:17)
>Хотелось бы добавления средствами грида, а не ХП или SQL комманд.
Это невозможно.


 
Девушка ©   (2005-09-19 12:06) [12]


> Это невозможно.

В смысле не явно посылать команды а работать через IBDataset.Insert IBDataset.post и т.п.


 
Андрей Жук ©   (2005-09-19 12:07) [13]

Можешь использовать ХП


 
Sergey13 ©   (2005-09-19 12:15) [14]

2[12] Девушка ©   (19.09.05 12:06)
Я такие вещи иногда делаю так.
На отдельной форме кидаем нужные Едиты и грид если нужно. Грид призываю к отдельному датасету (я "люблю" RxMemoryData) с нужной структурой. При нажатии на "сохранить" делаю все как в [8], но через основные датасеты. И волки целы и овцы сыты.
Можно делать и так как ты. Но комитить каждое действие. Если по логике работы это допустимо, то в принципе ничего страшного.


 
msguns ©   (2005-09-19 12:48) [15]

Если речь идет о добавлении нового документа с двумя или более уровнями (фактурами), то имхо, следует разделять заголовок и "дочки".
Т.е. сначала юзер добавляет заголовок, он фиксируется в БД (короткая пишущая транзакция) и потом можно добавлять записи-дочки, подтвержение которых можно делать отдельными транзакциями либо "скопом" опять-же короткими пишущими транзакциями.
Какой путь выбрать - Вам виднее. Я бы советовал итти позаписным путем применительно к складу. Правда при этом придется ввести понятие "проведенный-непроведенный) документ, но это только добавить надежности и достоверности Вашим данным.

Какими копонентами работать - Вам виднее. Можно редактировать через грид (многие считают этот способ кульно-рульным), а можно использовать модальные формы с подтверждением вставки-изменения каждой записи.
Однако надо помнить, что объект TIBDataset сам делает подтверждение - откат транзакций (что требует от клиента доп.затрат на перехват разных BeforePost+AfterPost во избежании "фокусов" при "гуляющей" коррекции в гриде) и не дает такое 100 процентно контролируемое управление со стороны клиента, как пара TIBQuery+TIBSQL


 
Девушка ©   (2005-09-19 14:18) [16]


> Если речь идет о добавлении нового документа с двумя или
> более уровнями (фактурами), то имхо, следует разделять заголовок
> и "дочки".

OK. Если разделять, то достаточно ли будет прописать commit в AfterPost датасета?


 
msguns ©   (2005-09-19 14:29) [17]

А внимательно и вдумчиво прочитать 2-й абзац [15] ?


 
Девушка ©   (2005-09-19 14:47) [18]


> msguns ©   (19.09.05 14:29) [17]

Не совсем понятно, когда dataset сам откатывает/подтверждает транзакции.

А по поводу TIBQuery+TIBSQL дык это уже делалось... хочется новое освоить :)


 
Sergey13 ©   (2005-09-19 14:51) [19]

2[16] Девушка ©   (19.09.05 14:18)
Вместо commit используй CommitRetaining. Просто Commit закрывает транзакцию.


 
Девушка ©   (2005-09-19 16:42) [20]


> Вместо commit используй CommitRetaining.

Этого достаточно ? :)


 
Sergey13 ©   (2005-09-19 16:43) [21]

2[20] Девушка ©   (19.09.05 16:42)
>Этого достаточно ? :)
Для чего?


 
msguns ©   (2005-09-19 16:47) [22]

>Девушка ©   (19.09.05 16:42) [20]
>Этого достаточно ? :)

Нет, если Вы хотите, чтобы добавленная (измененная) запись встала на "свое" место в гриде (в порядке сортировки).
Да, если Вы хотите, чтобы добавленную (измененную) запись увидели другие пользователи (при переоткрытии своих запросов разумеется)


 
Sergey13 ©   (2005-09-19 16:51) [23]

2 [22] msguns ©   (19.09.05 16:47)
Если через TIBDataset делать, то вроде должна встать куда надо.


 
Девушка ©   (2005-09-19 20:07) [24]

Что-то не получается...

Итак в родительском датасете в AfterPost стоит
transaction.CommitRetaining;

Добавляем новую запись в родительский датасет. Говорим post. Новая запись появилась в выпадающем списке DBGridEH дочернего датасета (т.к. lookup поле). Выбираем в этом выпадающем списке ту новую родительскую запись. При попытке post-ть получаем ошибку внешнего ключа.
Что нужно сделать что-бы внешний ключ "увидел"  новую запись в родительской таблице?

Оба датасета завязаны на одну транзакцию.
Параметры транзакции
read_committed
rec_version
nowait


 
Девушка ©   (2005-09-19 20:11) [25]

Опытным путем выяснилось, что если в AfterPost кроме коммита родительский датасет сначала закрыть потом открыть (простой рефреш почему-то не сработал) то указанная ошибка не возникает.


 
Девушка ©   (2005-09-19 20:34) [26]

Но это - плохое решение т.к. приходится потом опять запись позиционировать. :(


 
msguns ©   (2005-09-20 09:16) [27]

Это нормальное решение для любой SQL-технологии

Refresh не перечитывает записи с сервера


 
Sergey13 ©   (2005-09-20 09:35) [28]

2[26] Девушка ©   (19.09.05 20:34)
Я тебе еще в [7] писал
>2.Получать ИДшник родителя можно (и лучше) ДО вставки.
Сделай так и вставляй его явно, а не получай при вставке тригером.


 
Девушка ©   (2005-09-20 09:59) [29]


> >2.Получать ИДшник родителя можно (и лучше) ДО вставки.
> Сделай так и вставляй его явно, а не получай при вставке
> тригером.

id-к получается через GeneratorField и Gen_ID в InsertSQL.


> Это нормальное решение для любой SQL-технологии
Почему для того что-бы вставить запись в датасет дочерней таблицы, приходится перчитывать родительскую? Нелогично...


 
Sergey13 ©   (2005-09-20 10:11) [30]

2[29] Девушка ©   (20.09.05 09:59)
ЕПРСТ. 8-)
Получи его ДО вставки
Select Gen_Id(gen_name,1) from RDB$DATABASE
В тригере поставь проверку на НУЛЛ
if new.id is null then new.id=Gen_Id(gen_name,1)

Получи ИД-ник заранее и потом вставляй явно.


 
msguns ©   (2005-09-20 10:27) [31]

>Девушка ©   (20.09.05 09:59) [29]
>Почему для того что-бы вставить запись в датасет дочерней таблицы, приходится перчитывать родительскую? Нелогично...

Чтобы вставить дочернюю таблицу новую запись с ID только что вставленной родительской записи на сервере, ничего перечитывать не надо.
А вот как работает FIBDataSet, точнее что и когда он там перечитывает - фиг его знает, однако что-то он делает "не так", потому и вылазит эксепшн.
Я сам им не пользуюсь именно потому, что не уверен на 100%, что он правильно "поймет", что я хочу. И приходится больше приноравливаться к его поведению, чем решать собственно стоящие задачи.
Ясно, что у Вас при связке Мастер-детал он при добавлении в гл.датасет что-то недоруливает.

Вот почему я и говорил, что для явного управления транзакциями лучше использовать TIBQuery.
Кстати, проверьте опции коннекта. Там не должно быть SnapShot. И сколько у вас используется объектов транзакций ?


 
Девушка ©   (2005-09-20 11:23) [32]


> Кстати, проверьте опции коннекта. Там не должно быть SnapShot.
>  И сколько у вас используется объектов транзакций ?

SnapShot-а нет. Транзакция одна
read_committed
rec_version
nowait


> Получи ИД-ник заранее и потом вставляй явно.

Как вставлять явно через DNGridEH?


 
Sergey13 ©   (2005-09-20 11:29) [33]

> Как вставлять явно через DNGridEH?
Опять вставлять через грид! 8-)
В InsertSQL
insrte into table_name(ID,......) values (:ID,....)
В BeforePost закататй в ИД-шник то что получишь от
Select Gen_Id(gen_name,1) from RDB$DATABASE
И тригер проверь. Должно быть условие на НУЛЛ.


 
Девушка ©   (2005-09-20 12:01) [34]


> Sergey13 ©   (20.09.05 11:29) [33]

Вопрос может быть глупый, но как этот прием решит сабжевую проблему? Ну добавлю запись с ID-м который будет сгенерирован явно... это мне даст лишь возможность locat-ть заново запись. Как сделать так, что-бы не пришлось переоткрывать родительский набор данных?


 
Sergey13 ©   (2005-09-20 12:08) [35]

2[34] Девушка ©   (20.09.05 12:01)
>Как сделать так, что-бы не пришлось переоткрывать родительский набор данных?
А зачем его потом переоткрывать если он будет соответствовать действительности? Ты же этот родительский ИДшник можешь в дочку писать сразу.


 
Johnmen ©   (2005-09-20 12:27) [36]

>id-к получается через GeneratorField и Gen_ID в InsertSQL.

Кстати, это и есть запрос на следующий id Sergey13 ©   (20.09.05 10:11) [30], просто неявный.

И вообще, что-то мусолится, мусолится одно и то же...:)



Страницы: 1 вся ветка

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

Наверх





Память: 0.55 MB
Время: 0.026 c
1-1128931136
Frostik
2005-10-10 11:58
2005.10.30
как сделать активной ячейку StringGrid


2-1128929639
alol
2005-10-10 11:33
2005.10.30
выделение строк в DBGrid


14-1128514686
IceBeerg
2005-10-05 16:18
2005.10.30
NOD32 - Win32/TrojanDownloader.Dadobra.EE


2-1128682889
Pasha L
2005-10-07 15:01
2005.10.30
Измениьт титл окна


3-1126851290
ZSergey
2005-09-16 10:14
2005.10.30
Помогите настроить кодировку ...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский