Будьте осторожны при хранении сложных типов в PropertyList!

В Optimizely CMS мы можем легко хранить списки как простых, так и сложных типов. Им легко управлять, он хорошо отображается в интерфейсе редактора, а также эффективно сохраняется и загружается.

Он поддерживается и документирован в Optimizely World для CMS и для Commerce.

Однако в этих опубликованных примерах кода существует проблема с производительностью. PropertyList не выполняет сравнение на равенство, если мы не укажем, как это сделать.

Пример

Давайте рассмотрим пример из реального мира.

На сайте Commerce Connect мы можем хранить список спецификаций продуктов на каждой странице продукта или варианта. Обычно это элементы «ключ-значение» переменного числа. Таким образом, мы могли бы также сохранить их как список пользовательских свойств.

Этот сайт Commerce Connect, вероятно, также будет синхронизировать данные каталога из внешней системы PIM или MDM.

Для простоты я предварительно загружаю все связанные элементы каталога из каталога Commerce. Затем для каждого поступающего продукта или варианта я ищу один и тот же элемент среди предварительно загруженных элементов. Затем я присваиваю входящие значения свойствам каталога.

Вот совсем небольшой вырез из такой импортной работы.

var variationClone = variationContent.CreateWritableClone();
variationClone.Color = colorFromPim;
variationClone.Specifications = specificationsFromPim
.Select(x => new SpecificationItem { Key = x.Key, Value = x.Value })
.ToList();
if (variationClone.IsModified)
{
_contentRepository.Publish(variationContent);
}

Когда вариант этого образца будет сохранен и опубликован?

Всегда. Потому что вариацияClone.IsModified всегда будет истинной.

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

Это приводит к появлению ненужных новых версий контента без реальных различий при каждом запуске задания.

Read more:  Как сохранить здоровье при лечении ВИЧ и на какие побочные эффекты следует обращать внимание

Решение

Простое решение — создать собственный компаратор для каждого свойства пользовательского списка.

В моем примере список свойств хранит эту простую запись СпецификацииItem.

public record SpecificationItem
{
public string Key { get; set; }
public string Value { get; set; }
}

Вот моя реализация соответствующего типа свойства. Обратите внимание, как оно переопределяет свойство ItemComparer.

[PropertyDefinitionTypePlugIn]
public class PropertySpecificationList : PropertyList
{
// Use our own item comparer implementation, which specifically check whether the property values are equal.
protected override IEqualityComparer ItemComparer => SpecificationItemComparer.Default;
}

И, наконец, здесь происходит волшебство.

public class SpecificationItemComparer : IEqualityComparer
{
// Initialize a static field for easy reuse.
public static readonly SpecificationItemComparer Default = new();

// Depending on your needs use string.Equals with explicit StringComparison value, instead of "==".
public bool Equals(SpecificationItem x, SpecificationItem y) =>
ReferenceEquals(x, y) || (x is not null && y is not null && x.Key == y.Key && x.Value == y.Value);

public int GetHashCode(SpecificationItem obj) =>
HashCode.Combine(obj.Key, obj.Value);
}

Это решение одинаково хорошо работает в Optimizely CMS и Commerce Connect.

Читайте также

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.