Читайте дальше...
Пакетная запись справочников через массив
// Пакетное создание и запись нескольких элементов справочника
Процедура ПакетнаяЗаписьСправочников()
МассивНоменклатуры = Новый Массив;
// Подготавливаем данные для новых элементов
Для Инд = 1 По 10 Цикл
НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
НовыйЭлемент.Наименование = "Товар " + Строка(Инд);
НовыйЭлемент.Артикул = "ART-" + Строка(Инд);
НовыйЭлемент.Владелец = Справочники.Номенклатура.НайтиПоНаименованию("Группа товаров");
МассивНоменклатуры.Добавить(НовыйЭлемент);
КонецЦикла;
// Пакетная запись
Попытка
НачатьТранзакцию();
Для Каждого Элемент Из МассивНоменклатуры Цикл
Элемент.Записать();
КонецЦикла;
ЗафиксироватьТранзакцию();
Сообщить("Успешно записано " + Строка(МассивНоменклатуры.Количество()) + " элементов");
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка при пакетной записи: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Пакетная запись документов с проводками
// Пакетное создание и проведение документов
Процедура ПакетнаяЗаписьДокументов()
ДокументыДляЗаписи = Новый Массив;
Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка");
// Создаем несколько документов
Для Ном = 1 По 5 Цикл
Док = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
Док.Дата = ТекущаяДата();
Док.Контрагент = Контрагент;
Док.СуммаДокумента = Ном * 10000;
// Добавляем табличную часть
Док.Товары.Добавить();
Док.Товары[0].Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию("Ноутбук");
Док.Товары[0].Количество = Ном;
Док.Товары[0].Цена = 50000;
Док.Товары[0].Сумма = Ном * 50000;
ДокументыДляЗаписи.Добавить(Док);
КонецЦикла;
// Пакетная запись и проведение
Попытка
НачатьТранзакцию();
Для Каждого Документ Из ДокументыДляЗаписи Цикл
Документ.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;
ЗафиксироватьТранзакцию();
Сообщить("Записано и проведено документов: " + Строка(ДокументыДляЗаписи.Количество()));
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Пакетная запись через ОбъектМенеджер
// Использование ОбъектМенеджер для пакетной записи разнотипных объектов
Процедура ПакетнаяЗаписьРазнотипныхОбъектов()
Менеджер = Новый ОбъектМенеджер;
// Добавляем новый справочник
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКонтрагент.Наименование = "Новый контрагент " + Формат(ТекущаяДата(), "ДФ=yyyyMMddHHmmss");
НовыйКонтрагент.ИНН = "770000000001";
Менеджер.Добавить(НовыйКонтрагент);
// Добавляем новый документ
НовыйДокумент = Документы.СчетНаОплату.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Контрагент = НовыйКонтрагент.Ссылка;
НовыйДокумент.Сумма = 50000;
Менеджер.Добавить(НовыйДокумент);
// Добавляем изменение существующего элемента
Существующий = Справочники.Номенклатура.НайтиПоНаименованию("Ноутбук");
Если Существующий <> Неопределено Тогда
ОбъектДляИзменения = Существующий.ПолучитьОбъект();
ОбъектДляИзменения.Комментарий = "Изменен при пакетной записи";
Менеджер.Добавить(ОбъектДляИзменения);
КонецЕсли;
// Пакетная запись
Попытка
Результат = Менеджер.Записать();
Если Результат.Количество() > 0 Тогда
Сообщить("Успешно записано объектов: " + Строка(Результат.Количество()));
Для Каждого Объект Из Результат Цикл
Сообщить("Записан объект: " + Строка(Объект));
КонецЦикла;
КонецЕсли;
Исключение
Сообщить("Ошибка пакетной записи: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Пакетная запись с предварительной проверкой
// Пакетная запись объектов с проверкой заполнения реквизитов
Функция ПроверитьИЗаписатьОбъекты(МассивОбъектов)
КоличествоОшибок = 0;
МассивДляЗаписи = Новый Массив;
// Предварительная проверка
Для Каждого Объект Из МассивОбъектов Цикл
Неправильный = Ложь;
СообщенияОшибок = "";
// Проверка обязательных реквизитов
Если Объект.Свойство("Наименование") И ПустаяСтрока(Объект.Наименование) Тогда
Неправильный = Истина;
СообщенияОшибок = СообщенияОшибок + "Не заполнено наименование; ";
КонецЕсли;
Если Объект.Свойство("Родитель") И Объект.Родитель = Неопределено Тогда
Неправильный = Истина;
СообщенияОшибок = СообщенияОшибок + "Не указан родитель; ";
КонецЕсли;
// Проверка уникальности кода/наименования
Попытка
Если Объект.ТипОбъекта() = ТипСправочника() Тогда
Существует = Объект.Ссылка.НайтиПоНаименованию(Объект.Наименование);
Если Существует <> Неопределено И Существует <> Объект.Ссылка Тогда
Неправильный = Истина;
СообщенияОшибок = СообщенияОшибок + "Элемент с таким наименованием уже существует; ";
КонецЕсли;
КонецЕсли;
Исключение
// Игнорируем, если метод не поддерживается
КонецПопытки;
Если Неправильный Тогда
КоличествоОшибок = КоличествоОшибок + 1;
Сообщить("Объект " + Объект + " пропущен: " + СообщенияОшибок);
Продолжить;
КонецЕсли;
МассивДляЗаписи.Добавить(Объект);
КонецЦикла;
// Запись проверенных объектов
Попытка
НачатьТранзакцию();
Для Каждого Объект Из МассивДляЗаписи Цикл
Объект.Записать();
КонецЦикла;
ЗафиксироватьТранзакцию();
Возврат "Успешно записано " + Строка(МассивДляЗаписи.Количество()) +
" из " + Строка(МассивОбъектов.Количество()) +
". Ошибок: " + Строка(КоличествоОшибок);
Исключение
ОтменитьТранзакцию();
Возврат "Ошибка записи: " + ОписаниеОшибки();
КонецПопытки;
КонецФункции
// Пример использования
Процедура ТестПакетнойЗаписи()
Массив = Новый Массив;
// Создаем корректные и некорректные объекты
Объект1 = Справочники.Номенклатура.СоздатьЭлемент();
Объект1.Наименование = "Тестовый товар";
Объект1.Родитель = Справочники.Номенклатура.НайтиПоНаименованию("Группа товаров");
Массив.Добавить(Объект1);
Объект2 = Справочники.Номенклатура.СоздатьЭлемент();
Объект2.Наименование = ""; // Ошибка: пустое наименование
Массив.Добавить(Объект2);
Результат = ПроверитьИЗаписатьОбъекты(Массив);
Сообщить(Результат);
КонецПроцедуры
Пакетная запись с использованием обмена данными
// Пакетная запись объектов из внешнего источника
Процедура ПакетнаяЗаписьИзВнешнегоИсточника()
// Эмуляция получения данных из XML/JSON
ВнешниеДанные = ПолучитьДанныеИзВнешнегоИсточника();
// Массив для записи
ОбъектыДляЗаписи = Новый Массив;
Для Каждого СтрокаДанных Из ВнешниеДанные Цикл
// Определяем тип объекта
Если СтрокаДанных.ТипОбъекта = "Справочник.Контрагенты" Тогда
Объект = Справочники.Контрагенты.СоздатьЭлемент();
// Заполняем реквизиты
Объект.Наименование = СтрокаДанных.Наименование;
Объект.ИНН = СтрокаДанных.ИНН;
Объект.КПП = СтрокаДанных.КПП;
// Поиск родителя
Если ЗначениеЗаполнено(СтрокаДанных.Группа) Тогда
Группа = Справочники.Контрагенты.НайтиПоНаименованию(СтрокаДанных.Группа);
Если Группа <> Неопределено Тогда
Объект.Родитель = Группа;
КонецЕсли;
КонецЕсли;
ОбъектыДляЗаписи.Добавить(Объект);
ИначеЕсли СтрокаДанных.ТипОбъекта = "Справочник.Номенклатура" Тогда
Объект = Справочники.Номенклатура.СоздатьЭлемент();
Объект.Наименование = СтрокаДанных.Наименование;
Объект.Артикул = СтрокаДанных.Артикул;
Объект.БазоваяЕдиницаИзмерения = Справочники.ЕдиницыИзмерения.НайтиПоКоду(СтрокаДанных.Единица);
ОбъектыДляЗаписи.Добавить(Объект);
КонецЕсли;
КонецЦикла;
// Настройки обмена для пакетной записи
Обмен = Новый ОбменДанными;
Обмен.ЗагружатьНайденныеДанные = Истина;
Попытка
НачатьТранзакцию();
Для Каждого Объект Из ОбъектыДляЗаписи Цикл
// Используем обмен для поиска существующих
Найденный = Обмен.НайтиПоСсылке(Объект.Ссылка);
Если Найденный <> Неопределено Тогда
ЗаполнитьЗначенияСвойств(Найденный, Объект);
Найденный.Записать();
Иначе
Объект.Записать();
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Сообщить("Загружено объектов: " + Строка(ОбъектыДляЗаписи.Количество()));
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка загрузки: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Функция ПолучитьДанныеИзВнешнегоИсточника()
// Возвращает таблицу значений с внешними данными
// Ради примера возвращаем пустую таблицу
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("ТипОбъекта");
Результат.Колонки.Добавить("Наименование");
Результат.Колонки.Добавить("ИНН");
Результат.Колонки.Добавить("КПП");
Результат.Колонки.Добавить("Группа");
Возврат Результат;
КонецФункции
Пакетная запись с обработкой конфликтов
// Пакетная запись с разрешением конфликтов изменения
Процедура ПакетнаяЗаписьСРазрешениемКонфликтов()
// Массив объектов с возможными конфликтами
ОбъектыСИзменениями = ПолучитьОбъектыДляОбновления();
РезультатыЗаписи = Новый Соответствие;
Попытка
НачатьТранзакция(РежимУправленияТранзакцией.Сериализуемый);
Для Каждого Объект Из ОбъектыСИзменениями Цикл
// Проверяем, изменился ли объект другим пользователем
ТекущаяВерсия = Объект.Ссылка.ВерсияДанных;
Если ТекущаяВерсия <> Объект.ВерсияДанных Тогда
// Конфликт разрешаем по стратегии "оптимистичная блокировка"
Сообщить("Конфликт при записи " + Объект + ", версия изменилась");
// Получаем актуальную версию
АктуальныйОбъект = Объект.Ссылка.ПолучитьОбъект();
// Выбираем стратегию разрешения конфликта
Стратегия = ОпределитьСтратегиюРазрешенияКонфликта(Объект, АктуальныйОбъект);
Если Стратегия = "Клиент" Тогда
// Применяем изменения клиента поверх актуальных
ЗаполнитьЗначенияСвойств(АктуальныйОбъект, Объект);
АктуальныйОбъект.Записать();
РезультатыЗаписи.Вставить(Объект, "Разрешено в пользу клиента");
ИначеЕсли Стратегия = "Сервер" Тогда
// Оставляем серверную версию
РезультатыЗаписи.Вставить(Объект, "Оставлена серверная версия");
Иначе
// Слияние - требует ручного вмешательства
ВызватьИсключение "Требуется ручное разрешение конфликта для " + Объект;
КонецЕсли;
Иначе
// Конфликта нет - обычная запись
Объект.Записать();
РезультатыЗаписи.Вставить(Объект, "Успешно записан");
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Критическая ошибка: " + ОписаниеОшибки());
КонецПопытки;
// Выводим итоги
Для Каждого КлючЗначение Из РезультатыЗаписи Цикл
Сообщить("Объект: " + Строка(КлючЗначение.Ключ) + " -> " + КлючЗначение.Значение);
КонецЦикла;
КонецПроцедуры
Функция ОпределитьСтратегиюРазрешенияКонфликта(КлиентскийОбъект, СерверныйОбъект)
// Сравниваем, какие поля изменились
ЕстьИзмененияКлиента = Ложь;
ЕстьИзмененияСервера = Ложь;
// Пример сравнения для справочника
Для Каждого Колонка Из КлиентскийОбъект.СвойстваЦикл
Попытка
ЗначениеКлиента = КлиентскийОбъект[Колонка.Имя];
ЗначениеСервера = СерверныйОбъект[Колонка.Имя];
Если ЗначениеКлиента <> ЗначениеСервера Тогда
Если ЗначениеКлиента = КлиентскийОбъект.СтароеЗначение(Колонка.Имя) Тогда
ЕстьИзмененияСервера = Истина;
Иначе
ЕстьИзмененияКлиента = Истина;
КонецЕсли;
КонецЕсли;
Исключение
// Продолжаем
КонецПопытки;
КонецЦикла;
// Принимаем решение
Если ЕстьИзмененияКлиента И НЕ ЕстьИзмененияСервера Тогда
Возврат "Клиент";
ИначеЕсли НЕ ЕстьИзмененияКлиента И ЕстьИзмененияСервера Тогда
Возврат "Сервер";
ИначеЕсли ЕстьИзмененияКлиента И ЕстьИзмененияСервера Тогда
Возврат "Слияние";
Иначе
Возврат "Сервер";
КонецЕсли;
КонецФункции
Функция ПолучитьОбъектыДляОбновления()
// Возвращает массив объектов для пакетной записи
Возврат Новый Массив;
КонецФункции
Пакетная запись с использованием фоновых заданий
// Асинхронная пакетная запись больших массивов объектов
Процедура ЗапуститьПакетнуюЗаписьВФоне()
// Подготавливаем данные для записи
ДанныеДляЗаписи = ПодготовитьМассивОбъектов(1000); // 1000 объектов
// Разбиваем на порции
РазмерПорции = 100;
КоличествоПорций = Цел(ДанныеДляЗаписи.Количество() / РазмерПорции) +
?(ДанныеДляЗаписи.Количество() % РазмерПорции > 0, 1, 0);
Для НомерПорции = 1 По КоличествоПорций Цикл
НачалоПорции = (НомерПорции - 1) * РазмерПорции;
КонейПорции = Мин(НачалоПорции + РазмерПорции - 1, ДанныеДляЗаписи.Количество() - 1);
Порция = Новый Массив;
Для Инд = НачалоПорции По КонейПорции Цикл
Порция.Добавить(ДанныеДляЗаписи[Инд]);
КонецЦикла;
// Сохраняем порцию в хранилище
АдресПорции = ПоместитьВХранилище(Порция);
// Запускаем фоновое задание для каждой порции
Параметры = Новый Структура;
Параметры.Вставить("АдресДанных", АдресПорции);
Параметры.Вставить("НомерПорции", НомерПорции);
ФоновоеЗадание = РасширенияРаботыСФоновымиЗаданиями.ВыполнитьФоновоеЗадание(
"ОбработатьПорциюОбъектов",
Параметры,
"Пакетная запись порции " + Строка(НомерПорции));
Если ФоновоеЗадание = Неопределено Тогда
Сообщить("Ошибка запуска фонового задания для порции " + Строка(НомерПорции));
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Эта процедура выполняется в фоновом задании
Процедура ОбработатьПорциюОбъектов(ПараметрыЗадания) Экспорт
АдресХранилища = ПараметрыЗадания.АдресДанных;
НомерПорции = ПараметрыЗадания.НомерПорции;
МассивОбъектов = ПолучитьИзХранилища(АдресХранилища);
Если МассивОбъектов = Неопределено Или МассивОбъектов.Количество() = 0 Тогда
ЗаписьЖурналаРегистрации("Пакетная запись", "Порция " + Строка(НомерПорции) + " пуста");
Возврат;
КонецЕсли;
Попытка
НачатьТранзакцию();
Для Каждого Объект Из МассивОбъектов Цикл
// Проверка перед записью
Если Объект.Этогруппа Тогда
Продолжить;
КонецЕсли;
Объект.Записать();
КонецЦикла;
ЗафиксироватьТранзакцию();
ЗаписьЖурналаРегистрации("Пакетная запись",
"Порция " + Строка(НомерПорции) + ": записано " +
Строка(МассивОбъектов.Количество()) + " объектов");
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("Ошибка пакетной записи",
"Порция " + Строка(НомерПорции) + ": " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Функция ПодготовитьМассивОбъектов(КоличествоОбъектов)
Массив = Новый Массив;
Для Инд = 1 По КоличествоОбъектов Цикл
НовыйОбъект = Справочники.ВременныеОбъекты.СоздатьЭлемент();
НовыйОбъект.Наименование = "Временный объект " + Строка(Инд);
НовыйОбъект.ДатаСоздания = ТекущаяДата();
Массив.Добавить(НовыйОбъект);
КонецЦикла;
Возврат Массив;
КонецФункции
Процедура ЗаписьЖурналаРегистрации(Событие, Комментарий)
Запись = Новый ЗаписьЖурналаРегистрации;
Запись.Событие = Событие;
Запись.Комментарий = Комментарий;
Запись.Записать();
КонецПроцедуры
Примечания
// Важные особенности пакетной записи объектов:
// 1. Всегда используйте транзакции для обеспечения целостности данных
// 2. При пакетной записи большого количества объектов разбивайте их на порции
// 3. ОбъектМенеджер позволяет записывать разнотипные объекты в одной транзакции
// 4. Перед пакетной записью рекомендуется проводить предварительную валидацию
// 5. При конфликтах используйте стратегии оптимистических блокировок
// 6. Для длительных операций применяйте фоновые задания
// 7. Всегда обрабатывайте исключения и откатывайте транзакции при ошибках
// 8. При работе с большими массивами следите за потреблением памяти
// 9. Используйте режим "Сериализуемый" для транзакций с критическими данными
// 10. После пакетной записи обязательно обновляйте кэш ссылочных данных








