Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 49 additions & 11 deletions src/Классы/КоннекторInMemory.os
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,21 @@
Процедура Сохранить(ОбъектМодели, Сущность) Экспорт

Событие = НачатьЗапрос("INSERT", ОбъектМодели);

// Строка базы собирается до блокировки: конструктор класса сущности - пользовательский код, а
// значения колонок берутся из полей сохраняемого объекта и базы не касаются. Упади сборка, в
// общей таблице не останется недописанной строки, а идентификатор не будет выдан.
Попытка
СущностьВБД = СобратьСущностьВБД(ОбъектМодели, Сущность);
Исключение
ЗавершитьЗапрос(Событие, ИнформацияОбОшибке());
ВызватьИсключение;
КонецПопытки;

Блокировка.Запись().Заблокировать();

Попытка
ЗаписатьСущность(ОбъектМодели, Сущность);
ЗаписатьСущность(ОбъектМодели, Сущность, СущностьВБД);
Исключение
Блокировка.Запись().Разблокировать();
ЗавершитьЗапрос(Событие, ИнформацияОбОшибке());
Expand All @@ -197,13 +208,41 @@

КонецПроцедуры

// Создает объект строки базы и переносит в него значения всех колонок, кроме идентификатора:
// идентификатор может выдать только запись, под блокировкой.
//
// Параметры:
// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД.
// Сущность - Произвольный - Сохраняемая сущность.
//
// Возвращаемое значение:
// Произвольный - Объект строки базы без идентификатора.
//
Функция СобратьСущностьВБД(ОбъектМодели, Сущность)

СущностьВБД = Новый (ОбъектМодели.ТипСущности());
ИмяПоляИдентификатора = ОбъектМодели.Идентификатор().ИмяПоля;

Для Каждого Колонка Из ОбъектМодели.Колонки() Цикл
Если Колонка.ИмяПоля = ИмяПоляИдентификатора Тогда
Продолжить;
КонецЕсли;
Значение = ОбъектМодели.ПолучитьПриведенноеЗначениеПоля(Сущность, Колонка.ИмяПоля);
Рефлектор.УстановитьСвойство(СущностьВБД, Колонка.ИмяПоля, Значение);
КонецЦикла;

Возврат СущностьВБД;

КонецФункции

// Записывает сущность в таблицу кеша.
//
// Параметры:
// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД.
// Сущность - Произвольный - Объект (экземпляр класса, зарегистрированного в модели) для сохранения в БД.
// СущностьВБД - Произвольный - Объект строки базы со значениями колонок, см. СобратьСущностьВБД.
//
Процедура ЗаписатьСущность(ОбъектМодели, Сущность)
Процедура ЗаписатьСущность(ОбъектМодели, Сущность, СущностьВБД)

ИмяТаблицы = ОбъектМодели.ИмяТаблицы();

Expand Down Expand Up @@ -237,25 +276,24 @@

УчестьВыданныйИдентификатор(ИмяТаблицы, Идентификатор);

ИмяПоляИдентификатора = ОбъектМодели.Идентификатор().ИмяПоля;
Рефлектор.УстановитьСвойство(
СущностьВБД,
ИмяПоляИдентификатора,
ОбъектМодели.ПолучитьПриведенноеЗначениеПоля(Сущность, ИмяПоляИдентификатора)
);

Если ТипЗнч(Идентификатор) = Тип("Число") Тогда
Идентификатор = Формат(Идентификатор, "ЧГ=");
КонецЕсли;

// Строка добавляется последней, когда все ее значения уже готовы.
СтрокаТЗ = Таблица.Найти(Идентификатор, "_Идентификатор");

Если СтрокаТЗ = Неопределено Тогда
СтрокаТЗ = Таблица.Добавить();
КонецЕсли;

СущностьВБД = Новый (ОбъектМодели.ТипСущности());

Для Каждого Колонка Из ОбъектМодели.Колонки() Цикл
Значение = ОбъектМодели.ПолучитьПриведенноеЗначениеПоля(
Сущность,
Колонка.ИмяПоля);
Рефлектор.УстановитьСвойство(СущностьВБД, Колонка.ИмяПоля, Значение);
КонецЦикла;

СтрокаТЗ._Идентификатор = Идентификатор;
СтрокаТЗ._Сущность = СущностьВБД;

Expand Down
61 changes: 61 additions & 0 deletions tests/КоннекторInMemory.os
Original file line number Diff line number Diff line change
Expand Up @@ -653,3 +653,64 @@
Ожидаем.Что(НайденныеСтроки, "Коннектор работает после ошибок").ИмеетДлину(1);

КонецПроцедуры

// Таблица общая у всех коннекторов подключения. Сохранение, упавшее на вычислении значения колонки,
// не должно оставить в ней недописанную строку: иначе поиск ломается у всех, кто работает с базой.
//
&Тест
Процедура УпавшееСохранениеНеОставляетНедописаннойСтроки() Экспорт

// Дано
МодельДанных = Новый МодельДанных();
ОбъектМодели = МодельДанных.СоздатьОбъектМодели(Тип("СущностьСоВсемиТипамиКолонок"));
Коннектор.ИнициализироватьТаблицу(ОбъектМодели);

Сохраненная = Новый СущностьСоВсемиТипамиКолонок;
Сохраненная.Целое = 1;
Коннектор.Сохранить(ОбъектМодели, Сохраненная);

Сломанная = Новый СущностьСоВсемиТипамиКолонок;
Сломанная.Целое = 2;
// В ссылочном поле не сущность: значение колонки не вычислить.
Сломанная.Ссылка = "не сущность";

ПараметрыСохранения = Новый Массив;
ПараметрыСохранения.Добавить(ОбъектМодели);
ПараметрыСохранения.Добавить(Сломанная);

// Когда
Ожидаем.Что(Коннектор, "Сохранение с неверной ссылкой").Метод("Сохранить", ПараметрыСохранения)
.ВыбрасываетИсключение();

// Тогда
НайденныеСтроки = Коннектор.НайтиСтрокиВТаблице(ОбъектМодели, Новый ОпцииПоиска());
Ожидаем.Что(НайденныеСтроки, "Поиск видит только сохраненную строку").ИмеетДлину(1);

ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(СтрокаСоединения);
ПараметрыЗадания.Добавить(ОбъектМодели);
Задание = ФоновыеЗадания.Выполнить(ЭтотОбъект, "ПосчитатьСтрокиВДругомПотоке", ПараметрыЗадания, Истина);
ТестовыеУтилиты.ДождатьсяЗадания(Задание);

Ожидаем.Что(Задание.ИнформацияОбОшибке, "Поиск в другом потоке не упал").Равно(Неопределено);
Ожидаем.Что(Задание.Результат, "Другой поток видит только сохраненную строку").Равно(1);

КонецПроцедуры

// Считает строки таблицы своим коннектором той же базы. Выполняется фоновым заданием.
//
// Параметры:
// СтрокаСоединенияБазы - Строка - Строка подключения базы теста.
// ОбъектМодели - ОбъектМодели - Модель таблицы.
//
// Возвращаемое значение:
// Число - Число строк таблицы.
//
Функция ПосчитатьСтрокиВДругомПотоке(Знач СтрокаСоединенияБазы, ОбъектМодели) Экспорт

КоннекторПотока = Новый КоннекторInMemory();
КоннекторПотока.Открыть(СтрокаСоединенияБазы, Новый Массив);

Возврат КоннекторПотока.НайтиСтрокиВТаблице(ОбъектМодели, Новый ОпцииПоиска()).Количество();

КонецФункции
Loading