Изменение поля карточки через низкоуровневое API
Изменение поля карточки через низкоуровневое API¶
Рассмотрим ситуацию, когда требуется прочитать и изменить секции карточки в условиях высокой нагрузки. Например, разрабатывается интеграционный сервис, который может вызываться сотни раз в секунду для разных карточек. Только при наличии очень высоких требований к производительности можно использовать низкоуровневое API карточек из пространства имён Tessa.Cards.ComponentModel.
Note
В подавляющем большинстве случаев достаточно использовать высокоуровневое API ICardRepository. Для оптимизации же можно отключить расширения, т.е. получить объект из Unity с указанием имени CardRepositoryNames.Default. При этом не будут проверяться права доступа к карточке, не будет записи в лог аудита и других действий, выполняемых в расширениях платформы, типового решения или расширениях для вашего проекта.
В классе расширения или в классе веб-сервиса, в котором нужно прочитать карточку через низкоуровневое API, укажем поля, которые заполним в конструкторе из Unity:
private readonly ISession session;
private readonly ICardMetadata cardMetadata;
private readonly ICardTransactionStrategy transactionStrategy;
private readonly ICardGetStrategy getStrategy;
private readonly ICardStoreExecutionStrategy storeExecutionStrategy;
Также укажем статическое поле класса для объекта логирования:
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
В методе, в котором требуется изменить карточку, укажем следующий код. Пояснения к коду приведены в комментариях.
Guid cardID = ...;
var validationResult = new ValidationResultBuilder();
// выполняемся в блокировке на запись карточки, чтобы параллельно никто не мог загружать и изменять карточку
bool success = this.transactionStrategy
.ExecuteInWriterLock(
cardID,
CardComponentHelper.DoNotCheckVersion,
validationResult,
p =>
{
// загружаем системную информацию из таблицы Instances
CardGetContext getContext = this.getStrategy
.TryLoadCardInstance(
cardID,
p.DbScope.Db,
cardMetadata,
validationResult);
if (getContext == null)
{
p.ReportError = true;
return;
}
// нужны только секции DocumentCommonInfo и OutgoingRefDocs, исключаем остальные
// в getContext.CardMetadata.Sections лежат только секции загруженного типа карточки
getContext.SectionsToExclude.AddRange(
getContext.CardMetadata.Sections
.Where(x => x.Name != "DocumentCommonInfo" && x.Name != "OutgoingRefDocs")
.Select(x => x.ID)
.ToArray());
// загружаем все секции карточки, кроме тех, которые мы исключили
if (!this.getStrategy.LoadSections(getContext))
{
p.ReportError = true;
return;
}
// изменяем карточку: здесь может быть любая логика, связанная с изменением полей,
// используя DynamicEntries или Fields для строковых секций или строк в коллекционных секциях
// (для строк также нужно указать свойство State)
Card card = getContext.Card;
card.DynamicEntries.DocumentCommonInfo.FullNumber = "Дпр-00004";
// сохраняем карточку
card.RemoveAllButChanged();
var storeContext = new CardStoreContext(
card,
DateTime.UtcNow, // дата и время изменения карточки
this.session,
this.cardMetadata,
new ValidationResultBuilder(),
p.DbScope.Executor,
p.DbScope.BuilderFactory);
this.storeExecutionStrategy.StoreSections(storeContext);
// если есть ошибки при сохранении, то нужно откатить транзакцию
validationResult.Add(storeContext.ValidationResult);
if (!storeContext.ValidationResult.IsSuccessful())
{
// откатываем транзакцию
p.ReportError = true;
}
});
if (!success)
{
// логируем ошибки
logger.LogResult(validationResult.Build());
}