2011-01-27 2 views
1

У меня есть приложение C#, которое должно вставлять одну родительскую запись и, по меньшей мере, четыре записи детей в иерархическом порядке. IOW, родительский контракт применяется к одному или нескольким местоположениям, каждое место имеет один или несколько элементов, каждый элемент имеет одну или несколько служб, и каждая услуга имеет одно или несколько требований. Приложение сначала получает набор порядковых номеров Oracle, по одному от каждой последовательности таблиц для каждой записи. По какой-либо причине (устаревшая база данных) каждая запись имеет не только порядковый номер ее родителя, но и порядковый номер контракта.Вставка записей родителя/ребенка в транзакции A

Итак, код начинает транзакцию, вставляет родителя с порядковым номером родительского уровня, затем пытается вставить запись местоположения, уже заполненную как родительским номером, так и FK, и его собственный порядковый номер таблицы. Тем не менее, я получаю ошибку Oracle-02291, которую нарушает FK, потому что родительский номер не найден.

INSERT into Contracts (contract_sequence_number, ...) values (10437, ...); 
INSERT into Locations (location_sequence_number, contract_sequence_number, ...) 
    values (23733, 10437, ...); 
... 

Я предполагаю, что это происходит потому, что родитель не был совершен и поэтому недоступен. Однако я не могу зафиксировать родителя, если никаких ошибок дочерних записей, поэтому фиксация перед дочерней вставкой отсутствует.

Я знаю, что это такой общий сценарий, ответ должен быть pre-noob. Но все ответы, которые я нашел, до сих пор подразумевают, что номер родительской последовательности найден «в таблице», чтобы удовлетворить FK.

Любые мысли о том, как я исправить это, очень ценятся.

Рэнди

+0

Вы не можете разделить свою вставку на две отдельные функции? Вернуть идентификатор родительской записи в код C#, а затем использовать ее для выполнения дочерних вставок? – TheGeekYouNeed

+0

Фактически, они находятся в двух отдельных функциях внутри одного и того же блока транзакций. Я просто показываю два оператора SQL, чтобы прояснить мою проблему. – EoRaptor013

ответ

0

Благодарим всех вас за ввод. Оказалось (как я подозревал), это было плохо. Оказывается, есть две очень похожие схемы, и соединение, которое я использовал, имеет доступ к обоим. Обе схемы имеют таблицы с тем же именем. По причинам, не ясным для меня, родитель вставлял в одну шмею, но ребенок пытался вставить в другую схему. Конечно, это не могло решить отношения PK/FK!

Снова, спасибо.

0

любые из вставок, сделанных с установкой PRAGMA_AUTONOMOUS_TRANSACTION? мне кажется, что ожидающие коммиты должны быть видны всей транзакции.

О, еще одна мысль - если вставки находятся в триггере PRE, попробуйте переместить их на триггер POST.

+0

Приложение находится на C#, хотя функции сохранения создают объекты Oracle Command. Мне нужно будет прочитать PRAGMA_AUTONOMOUS_TRANSACTION. Мысль о том, что это просто процедура Oracle. – EoRaptor013

+0

PRAGMA - это не нормальная вещь, но она, безусловно, создаст аналогичную ситуацию, о которой вы описываете, если она существует. Наверное, не о чем беспокоиться. Если вы издаете много последовательных вставок вне триггера, я предлагаю COMMIT между ними, что позволит увидеть видимость. – Randy

1

В дочерних вставках будет обнаружен любой родитель, который был либо зафиксирован, либо был ранее вставлен одной и той же транзакцией (независимо от того, совершена она или нет).

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

То есть вы публикуете заявление INSERT в контракты (contract_sequence_number, ...) значения (10437, ...);

, но триггер определяет новый contract_sequence_number из последовательности и фактически дает ему первичный ключ 10438 (или что-то еще).

Другой проблемой может быть любой уровень ORM, который устраняет проблему, не выдавая вставки в правильном порядке или используя разные соединения из пула для одной транзакции.

Также проверьте, что вставка родителя не вернула ошибку.

Попробуйте выполнить пробную транзакцию через обычный клиент (например, SQL * Plus) и посмотрите, работает ли это. Если там вставлена ​​дочерняя вставка, просто запросите самую последнюю запись из контракта (например, где contract_sequence_number> 10400) и посмотрите, удалось ли вставить.

+0

Отличная мысль о триггере вставки. Хотя я его не нашел, я попрошу нашего эксперта по знаниям. – EoRaptor013

+0

Кроме того, имеет смысл, что ребенок должен видеть родительский идентификатор, если он находится в одной транзакции. Вы знаете, действительно ли это справедливо для Oracle? Мои две вставки, безусловно, находятся в одной транзакции, тем не менее я нарушаю FK, родитель не найден, хотя я подтверждаю, что родительская запись вставлена ​​правильно. Как обычно эта проблема с родителем/дочерним элементом обрабатывается? – EoRaptor013

0

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

1

Установите ваши Fk контрсил к deferrable initially deferred.

Кроме того, вам необходимо сделать как/все вставки внутри одной транзакции. Если вы используете ODAC для C#, сначала начинайте OracleTransaction, делайте вставки, а затем commit() и dispose(). Убедитесь, что в блоке catch вызывается rollback() и dispose() для транзакции.

См. here для PDF-версии документации Oracle Data Access Components (11g).

Надеюсь, что поможет

+0

Спасибо. Это в значительной степени то, что я делаю. В C# я начинаю транзакцию, вставляю родителя, а затем пытаюсь вставить первый ребенок. Я не уверен, что могу изменить ограничение FK, как вы предлагаете. DBA иногда не являются наиболее кооперативными. – EoRaptor013

+0

О, да, у меня есть откат в уловке. – EoRaptor013

+0

Да, администраторы баз данных должны помогать в развитии imo (и, в конечном счете, в создании компании $$$). К сожалению, некоторые так не думают ... – tbone

Смежные вопросы