Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.10.30;
Скачать: CL | DM;

Вниз

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

 
Девушка ©   (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;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.449 c
8-1118066972
TORT
2005-06-06 18:09
2005.10.30
ГРУГЛАЯ ФОРМА


2-1128435019
Dell3r
2005-10-04 18:10
2005.10.30
Interbase


3-1126694978
erika
2005-09-14 14:49
2005.10.30
Соединение с ервером через инет


14-1128533837
Prohodil Mimo
2005-10-05 21:37
2005.10.30
Вопрос по лицензии Delphi !!!


2-1128877527
дендроид
2005-10-09 21:05
2005.10.30
как извлечь корень n-ной степени?