Еще один день, еще одна находка для ламера)



Если на клиенте вы перед сохранением записи (отправкой email) проводите какие-то манипуляции с содержимым объекта (например, меняете тело письма) и при сохранении получаете ошибку "Violation of PRIMARY KEY constraint ... . Cannot insert duplicate key in object ... . The duplicate key value is ... . The statement has been terminated.", то скорее всего ваша запись каким-то образом сохраняется дважды с одним и тем же id.



Мне не удалось достоверно определить, что это на самом деле попытка сохранения двух записей с одинаковым id, т.к. мы работаем на облачной версии и здесь нет возможности отладки серверного кода и нет доступа к SQL-профайлеру. Вместе с тем, если у вас так же, как и у меня, с клиента уходит одно сообщение о сохранении записи, а возвращается ошибка о попытке сохранении двух записей, у меня для вас хорошая новость :)



Попробуйте изменять поля объекта в тихом режиме. Для этого в this.set("Поле", значение) добавьте объект options = {silent: true} вот таким образом: this.set("Поле", значение, {silent: true}), это сохранит поле без запуска триггеров, которые срабатывают при изменении записи и в некоторых случаях поможет избежать указанной ошибки.



Скорее всего при изменении полей объекта (даже через изменение его атрибутов с помощью this.set, что любопытно на мой взгляд) срабатывает триггер, который приводит к сохранению записи, которую вы пытаетесь сохранить снова буквально секундой позже, что и приводит к ошибке. Если вы знаете, почему на самом деле так происходит, напишите, интересно подсмотреть что же все-таки у этого механизма под капотом :)



Удачного дня)

Нравится

Поделиться

2 комментария

Егор, посмотреть весь оборот данных между браузером-клиентом и веб-сервером можно в «инструментах разработчика» в браузере или в отдельной программе Fiddler. Если Ваша гипотеза верна, будет видно два запроса на добавление там, где по смыслу должен быть один, и можно будет понять, при каких действиях в браузере уходит первый.

Кстати, строго говоря, под триггером обычно имеют в виду логику на уровне SQL-сервера. Она есть не на всех таблицах, чаще используют логику на уровне объектов и БП, но иногда всё же есть и сработает при любом сохранении, если его специально не отключить.

та-даааам!

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

 

ВАЖНО

Запрещено обращаться к полям ViewModel  напрямую по названию. Необходимо использовать методы get() и set(), так как в данных методах реализована генерация событий изменения свойств модели и, соответственно, задействован механизм связывания.

Соответственно, при вызове set() должна срабатывать вся логика, привязанная к событиям изменения. Если вы не хотите, чтобы эта логика отрабатывала, то нужно указать в аргументе options объект {silent: true}

Показать все комментарии