Неявные транзакции и отказ в записи

Тема в разделе "1C и всё что с ней связано", создана пользователем Истребитель, 21 дек 2010.

  1. Истребитель

    Истребитель Well-Known Member

    Регистрация:
    9 июн 2010
    Сообщения:
    110
    Симпатии:
    0
    Добрый день!

    Задача:
    Есть две сущности - Событие и Бронь.
    Событие (Справочник) это запись о том, когда клиент приходит в заведение
    Бронь (Документ) это данные о том, что под событие забронированы места (например, пять дорожек боулинга).
    На одно событие может не быть броней вообще (клиент просто заказал себе столик с едой для ДР) или быть несколько броней (боулинг, бильярд). Соответственно, связь по полю владелец (событие - владелец брони)

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

    При записи брони нужно проверить, что места для бронирования доступны, и занять их в регистрах сведений (регистр сведений говорит, доступно ли место на дату Х, каждая бронь одного места создает две записи в регистр, недоступно с начала брони и доступно с конца брони). Это делается в ПередЗаписью модуля объекта документа Бронь.
    При пометке на удаление события логично предложить также пометить на удаление все брони и наоборот, при снятии пометки - снять пометку с броней. Это делается в ПередЗаписью модуля объекта справочника Событие, после того, как проверено, что событие будет успешно записано, при этом сменится пометка удаления.

    Но при этом может быть ситуация, что сначла пометили на удаление событие и его брони, затем места забронировали другой бронью, затем снимаем пометку удаления с события - со снятием её с броней - при этом движения по брони не могут быть записаны потому, что места этой брони уже заняты.
    Такая бронь по моей идее останется без изменений, ибо ей будет установлено отказ=истина в ПередЗаписью.
    То есть например, под событие две брони, боулинг и бильярд, для бильярда столы всё ещё свободны а боулинг дорожки уже заняты, пометка удаления должна сняться с бильярда а на боулинге остаться.

    НО! 1С тут тупит.

    Вот код:
    Код ( (Unknown Language)):
    если ЗначениеЗаполнено(Документы.Бронь.НайтиПоРеквизиту("Событие",ссылка)) тогда
    Режим = РежимДиалогаВопрос.ДаНет;
    Ответ = Вопрос("Снята пометка удаления. Снять пометку на удаление также с Броней, оформленных на это событие?", Режим, 0);
    Если Ответ = КодВозвратаДиалога.Нет Тогда
    Возврат;
    КонецЕсли;

    ПараметрыОтбора = Новый Структура;
    ПараметрыОтбора.Вставить("Событие", Ссылка);
    Выборка=Документы.Бронь.Выбрать(,,ПараметрыОтбора);

    пока Выборка.Следующий() цикл

    докоб=Выборка.ПолучитьОбъект();
    докоб.ПометкаУдаления=Ложь;
    попытка                 
    докоб.Записать();
    исключение

    КонецПопытки;
    КонецЦикла;

    КонецЕсли;
    Идея простая - выбираем все доки по событию и ставим им пометку удаления
    Но при этом докоб.Записать() вызывает ОШИБКУ если отказ=истина внутри ПередЗаписью!

    Окей, я сделал попытку-исключение, но теперь Выборка.ПолучитьОбъект(); вызывает ошибку "в этой транзакции уже были ошибки!"

    Да какого хрена, что они были, что с того?

    Почитал интернет, говорят происходит неявная транзкция, то есть её НИКАК не остановить, не отменить и не начать заново! Офигенно.

    То есть нет НИКАКОГО способа реализовать то, что я хочу (чтобы те документы, которые в своём теле получат отказ, не записались - остались помеченными - а те, которые в своём теле не получат отказ, снялись с удаления), просто потому, что кто-то в 1С решил, что нужно убивать возможность делать получение объекта при установке отказ=истина? Мне нужно дублировать код проверки легальности записи брони (места не заняты) ещё и в событии чтобы не доходило до отказа, чтоли?

    Или я что-то упускаю, и есть вариант обойти эту гадость и сделать таки то, что мне нужно, без дупликации кода?
     
  2. unknown181538

    unknown181538 НеГуру
    1C Team

    Регистрация:
    28 дек 2008
    Сообщения:
    1.418
    Симпатии:
    0
    Хм... задачка...
    А если... создать в модуле документа "Бронь" процедуру "ВозможнаЗапись()", и вынести в нее проверку из "ПередЗаписью". Здесь:
    Код ( (Unknown Language)):
                 пока Выборка.Следующий() цикл

    докоб=Выборка.ПолучитьОбъект();
    Если ДокОб.ВозможнаЗапись() Тогда
    докоб.ПометкаУдаления=Ложь;          
    докоб.Записать();
    КонецЕсли;
    А для невозможности удалить "Бронь" интерактивно без проверки, вставить вызов той же процедуры в "ПередЗаписью()" формы.

    Запись документов при записи спр-ка, в целом идеологически не очень...
     
  3. evgenyatam

    evgenyatam Well-Known Member

    Регистрация:
    7 сен 2007
    Сообщения:
    175
    Симпатии:
    0
    используй явную транзакцию вокруг записи документа. транзакции могут вкладываться одна в другую до бесконечности.
     
  4. Gluk8888

    Gluk8888 Гость

    согласен на все 100, может стоит подумать в сторону изменения самой структуры базы данных и изменения алгоритма?
    ИМХО: может проще не отменять запись документа? т.к. событие бронирование было произведено и помеченный на удаление документ в принципе не несет смысловой нагрузки. может лучше делать на основании документа документ отмены бронирования? в котором будут обратные движение по регистрам? как-то так.
     
  5. allexus

    allexus Гость

    Либо документом бронирования делать оба движения в регистре (кстати, лучше Накопления)..
     

Поделиться этой страницей