Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Внешние ключи в контекст транзации. [D7, IB 7.1]


Страницы:   1 2

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

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

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

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


Johnmen   (2005-09-20 12:27:00) [1]

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

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

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


Sergey13   (2005-09-20 12:08:00) [2]

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


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


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

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


Sergey13   (2005-09-20 11:29:00) [4]

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


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


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

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


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

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


msguns   (2005-09-20 10:27:00) [6]

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

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

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


Sergey13   (2005-09-20 10:11:00) [7]

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)

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


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


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

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


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


Sergey13   (2005-09-20 09:35:00) [9]

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


msguns   (2005-09-20 09:16:00) [10]

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

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


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

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


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

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


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

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

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

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

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


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

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


msguns   (2005-09-19 16:47:00) [15]

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

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


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

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


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


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

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


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

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


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


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

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

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


msguns   (2005-09-19 14:29:00) [20]

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо