Вчера коллега спросил меня, как нам перенести свойства содержимого каталога. К сожалению, официального способа сделать это нет. Однако есть несколько неофициальных способов сделать это. Сегодня мы рассмотрим способ, который я лично рекомендую – с точки зрения его безопасности и обратной совместимости.
Допустим, у нас есть FashionProduct
с MSRP
недвижимость с типом Money
теперь мы хотели бы изменить его на Decimal
. Есть несколько хитрых способов сделать это, но все они требуют прямых манипуляций с базой данных, которых нам следует избегать – если это возможно.
Сначала нам понадобится этот фрагмент кода. он был «украдён» у моего коллеги и использовался бесчисленное количество раз. Вероятно, вы захотите добавить его в закладки, так как он, вероятно, пригодится в будущем (вероятно, мне следует сделать это самому, поскольку мне придется находить его каждый раз, когда мне понадобится). Это фрагмент для перемещения по структуре каталога в зависимости от желаемого типа контента.
public virtual IEnumerable GetEntriesRecursive(ContentReference parentLink, CultureInfo defaultCulture) where T : EntryContentBase
{
foreach (var nodeContent in LoadChildrenBatched(parentLink, defaultCulture))
{
foreach (var entry in GetEntriesRecursive(nodeContent.ContentLink, defaultCulture))
{
yield return entry;
}
}
foreach (var entry in LoadChildrenBatched(parentLink, defaultCulture))
{
yield return entry;
}
}
private IEnumerable LoadChildrenBatched(ContentReference parentLink, CultureInfo defaultCulture) where T : IContent
{
var start = 0;
while (true)
{
var batch = _contentLoader.GetChildren(parentLink, defaultCulture, start, 50);
if (!batch.Any())
{
yield break;
}
foreach (var content in batch)
{
// Don't include linked products to avoid including them multiple times when traversing the catalog
if (!parentLink.CompareToIgnoreWorkID(content.ParentLink))
{
continue;
}
yield return content;
}
start += 50;
}
}
Чтобы убедиться, что мы не загружаем много контента одновременно, размер пакета установлен 50, но это, конечно, можно настроить (на ваше усмотрение)!
Теперь самое интересное, где это действительно работает. Как только у нас будет контент, нам нужно будет перенести данные, это может быть просто, вот так
private void MigrateProperty(IEnumerable contents) where T: EntryContentBase
{
var batch = new List();
foreach(var content in contents)
{
var writeableClone = content.CreateWriteableClone();
Transform(writeableClone);
batch.Add(writeableClone);
}
_contentRepository.Publish(batch, PublishAction.SyncDraft);
}
С Transform
вы можете делать со значением свойства все, что захотите. Поскольку вы можете просто переименовать его, он ничего не сможет сделать, кроме как присвоить значение новому свойству. Или в случае, о котором мы упоминали вначале, конвертируйте Money
к Decimal
это простая задача(Money
это менее точная версия Decimal
). Обратите внимание: если вы выполняете преобразование между типами данных, например из double
к int
существует потенциальная потеря данных, но вы, вероятно, уже об этом знаете.
Последний шаг — опубликовать изменение. Из соображений производительности это, вероятно, лучшее, что вы можете Publish
метод расширения IContentRepository
и сохраните несколько материалов в одном пакете — размером 50 или 100. При этом будут пропущены такие вещи, как создание новых версий, для оптимальной производительности. Вы можете прочитать об этом здесь Новый простой API пакетного сохранения для коммерции | Оптимизировать разработчик C
Остается вопрос, где его разместить. В идеальном мире я бы сказал, что на этапе миграции (т. е. класс, реализующий IMigrationStep
), поэтому вы гарантируете, что ваши данные будут правильно перенесены до того, как будет запущено что-либо еще, например ваш новый код, который обращается к новому свойству, или индексирование вашего контента после миграции. Но если у вас большой каталог, это займет время, и, возможно, не стоит позволять пользователям ждать его завершения. Для этого имеет смысл сделать это в запланированном задании, и когда оно завершится, вы переключитесь.
Миграция свойств — непростая и быстрая задача, но ее можно выполнить относительно легко. Это также напоминает нам о моделировании — постарайтесь сделать все правильно с самого начала, чтобы нам не пришлось мигрировать. В конце концов, самый быстрый код — это код, который не нужно запускать!