Как работают транзакции SQL?

2

Я слишком долго не работал в SQL, но мне казалось, что я понял, что, обернув SQL-запросы внутри транзакции, все завершенные заявления или ни один из них не сделал. Вот моя проблема. У меня есть объект заказа, который имеет коллекцию lineitem. Позиции связаны с порядком. ORDERId. Я подтвердил, что все идентификаторы установлены и правильны, но когда я пытаюсь сохранить (вставить) порядок, я получаю . Оператор INSERT противоречил ограничению FOREIGN KEY "FK_OrderItemDetail_Order". Конфликт произошел в базе данных "MyData", таблице "dbo.Order", в столбце "OrderId".

код psuedo:

create a transaction
transaction.Begin()
Insert order
Insert order.LineItems <-- error occurs here
transaction.Commit

действительный код:

...
entity.Validate();
if (entity.IsValid)
{
    SetChangedProperties(entity);
    entity.Install.NagsInstallHours = entity.TotalNagsHours;
    foreach (OrderItemDetail orderItemDetail in entity.OrderItemDetailCollection)
    {
        SetChangedOrderItemDetailProperties(orderItemDetail);
    }
    ValidateRequiredProperties(entity);
    TransactionManager transactionManager = DataRepository.Provider.CreateTransaction();
    EntityState originalEntityState = entity.EntityState;
    try
    {
        entity.OrderVehicle.OrderId = entity.OrderId;
        entity.Install.OrderId = entity.OrderId;
        transactionManager.BeginTransaction();

        SaveInsuranceInformation(transactionManager, entity);
        DataRepository.OrderProvider.Save(transactionManager, entity);
        DataRepository.OrderItemDetailProvider.Save(transactionManager, entity.OrderItemDetailCollection);             if (!entity.OrderVehicle.IsEmpty)
        {
            DataRepository.OrderVehicleProvider.Save(transactionManager, entity.OrderVehicle);
        }
        transactionManager.Commit();
    }
    catch
    {
        if (transactionManager.IsOpen)
        {
            transactionManager.Rollback();
        }
        entity.EntityState = originalEntityState;
    }
}
...

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

  • 0
    Видя описание выше, кажется, что ваш идентификатор заказа не генерируется автоматически. Если он генерируется автоматически, то при запуске первого SQL-запроса в то время вы получите идентификатор заказа, который необходимо установить в строках заказа для успешного выполнения второго запроса.
  • 0
    Вы можете опубликовать полный код? В первом ADO.NET не было «внешней транзакции», и вы должны были передать ссылку на объект транзакции для каждой операции в качестве параметра. Если вы пропустите это, поведение, которое вы описываете, является обычным.
Показать ещё 1 комментарий
Теги:
.nettiers

6 ответов

1
Лучший ответ

Я заметил, что вы сказали, что используете NetTiers для генерации кода.

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

Удачи вам в вашей проблеме.

  • 0
    Удалил FK, сохранил таблицу, добавил FK обратно и заново сгенерировал скрипты. Успех. До этого я регенерировал дюжину раз, надеясь, что это решит проблему, и ничего, поэтому я не думаю, что это было потруднее, но сейчас это работает, поэтому я счастливый турист.
1

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

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

Вы определенно не хотите использовать две транзакции.

  • 0
    1. Да, нет места для закрытия соединения изнутри транзакции. 2. Я сам устанавливаю идентификатор перед сохранением записей и проверил после вставки ордера, чтобы убедиться, что идентификатор не был изменен SQL. 3. Не исключаю, что сделал что-то не так, но ограничение - это не что иное, как FK OrderItem.OrderId to PK Order.OrderId.
0

Похоже, что ваш оператор insert для lineItems неправильно устанавливает значение для заказа. Это должно быть результатом шага Insert order. Вы посмотрели (и протестировали) отдельные инструкции SQL?

Я не думаю, что ваша проблема имеет какое-то отношение к управлению транзакциями.

  • 0
    Я установил первичный ключ в порядке, прежде чем вставить его. Это то же значение после оператора вставки. У всех позиций также был установлен соответствующий orderid перед попыткой их вставить.
  • 0
    Что проверяет ограничение FK? Пожалуйста, добавьте больше информации, она может указывать на другую область, чем PK порядка таблицы ...
Показать ещё 2 комментария
0

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

  • 0
    Пожалуйста, поймите, что я не показывал обработку ошибок, откат транзакции и т. Д. Для краткости я попытался показать только краткое изложение проблемы без подробностей. Если окажется, что нужны подробности, я выложу реальный код
0

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

0

Ошибка выглядит так, что в LineItems не задан правильный FK OrderId, который был автогенерирован вводом заказа в таблицу заказов. Вы говорите, что вы проверили идентификаторы, вы также проверили FK в деталях заказа?

  • 0
    Да. Я использую идентификаторы GUID для идентификаторов, и первичный ключ и внешние ключи все установлены до открытия транзакции, и все они были проверены непосредственно перед и сразу после операторов вставки.
  • 0
    Затем следующая вещь, которую я проверю, - убедиться, что ограничение внешнего ключа, на которое ссылается сообщение об ошибке, на самом деле соединяет правильные две таблицы ... и что оно движется в правильном направлении. ... и между двумя правыми столбцами

Ещё вопросы

Сообщество Overcoder
Наверх
Меню