Exemplo n.º 1
0
        /// <exception cref="ArgumentNullException" />
        /// <exception cref="InvalidOperationException" />
        private void ProcessArticlesTree(Article newArticle, Article existingArticle, Content definition)
        {
            if (newArticle == null || !_filter.Matches(newArticle))
            {
                return;
            }
            if (!_filter.Matches(existingArticle))
            {
                existingArticle = null;
            }
            if (definition == null)
            {
                throw new ArgumentNullException(nameof(definition));
            }

            ValidateDates(newArticle, existingArticle);

            ArticleData newArticleUpdateData = new ArticleData
            {
                ContentId = definition.ContentId,
                Id        = newArticle.Id
            };

            List <int> plainFieldIds = definition.Fields
                                       .Where(x => x is PlainField)
                                       .Select(x => x.FieldId)
                                       .ToList();

            if (definition.LoadAllPlainFields)
            {
                plainFieldIds.AddRange(
                    _fieldService.List(definition.ContentId)
                    .Where(x => x.RelationType == RelationType.None &&
                           definition.Fields.All(y => y.FieldId != x.Id))
                    .Select(x => x.Id));
            }

            // TODO: исключаем Readonly поля
            var updatedFields = newArticle.Fields.Values
                                .OfType <PlainArticleField>()
                                .Where(x => plainFieldIds.Contains(x.FieldId.Value) &&
                                       (existingArticle == null ||
                                        existingArticle.Fields.Values
                                        .OfType <PlainArticleField>()
                                        .All(y => y.FieldId != x.FieldId || !HasEqualNativeValues(x, y))))
                                .Select(x => new FieldData {
                Id = x.FieldId.Value, Value = x.Value
            });

            newArticleUpdateData.Fields.AddRange(updatedFields);

            var associationFieldsInfo = (
                from fieldDef in definition.Fields.OfType <Association>()
                join field in newArticle.Fields.Values on fieldDef.FieldId equals field.FieldId
                select
                new
            {
                field,
                oldField = existingArticle?.Fields.Values.SingleOrDefault(x => x.FieldId == field.FieldId),
                fieldDef
            }).ToArray();

            foreach (var fieldToSyncInfo in associationFieldsInfo)
            {
                if (fieldToSyncInfo.fieldDef is BackwardRelationField backwardRelationFieldDef)
                {
                    BackwardArticleField oldField = (BackwardArticleField)fieldToSyncInfo.oldField;
                    BackwardArticleField field    = (BackwardArticleField)fieldToSyncInfo.field;

                    int[] idsToAdd = field.GetArticles(_filter)
                                     .Where(x => oldField == null || oldField.GetArticles(_filter).All(y => y.Id != x.Id))
                                     .Select(x => x.Id)
                                     .ToArray();

                    int[] idsToRemove = oldField?.GetArticles(_filter)
                                        .Select(x => x.Id)
                                        .Where(x => field.GetArticles(_filter).All(y => y.Id != x))
                                        .ToArray() ?? new int[0];

                    if (idsToAdd.Any())
                    {
                        _updateData.AddRange(idsToAdd.Select(x => new ArticleData
                        {
                            Id        = x,
                            ContentId = backwardRelationFieldDef.Content.ContentId,
                            Fields    = new List <FieldData>
                            {
                                new FieldData {
                                    Id = field.FieldId.Value, ArticleIds = new[] { newArticle.Id }
                                }
                            }
                        }));
                    }

                    if (idsToRemove.Any())
                    {
                        if (backwardRelationFieldDef.DeletingMode == DeletingMode.Delete)
                        {
                            foreach (int idToRemove in idsToRemove)
                            {
                                _articlesToDelete[idToRemove] = backwardRelationFieldDef.Content;
                            }
                        }
                        else
                        {
                            _updateData.AddRange(idsToRemove.Select(x => new ArticleData
                            {
                                Id        = x,
                                ContentId = backwardRelationFieldDef.Content.ContentId
                            }));
                        }
                    }
                }
                else if (fieldToSyncInfo.fieldDef is ExtensionField extensionFieldDef)
                {
                    ExtensionArticleField oldField = (ExtensionArticleField)fieldToSyncInfo.oldField;
                    ExtensionArticleField field    = (ExtensionArticleField)fieldToSyncInfo.field;

                    if (oldField == null || field.Value != oldField.Value)
                    {
                        newArticleUpdateData.Fields.Add(new FieldData
                        {
                            Id         = extensionFieldDef.FieldId,
                            Value      = field.Value,
                            ArticleIds = field.Item == null ? null : new[] { field.Item.Id }
                        });

                        if (oldField?.Item != null)
                        {
                            _articlesToDelete[oldField.Item.Id] = extensionFieldDef
                                                                  .ContentMapping[oldField.Item.ContentId];
                        }
                    }
                }
                else if (fieldToSyncInfo.field is SingleArticleField)
                {
                    SingleArticleField oldField       = (SingleArticleField)fieldToSyncInfo.oldField;
                    SingleArticleField field          = (SingleArticleField)fieldToSyncInfo.field;
                    EntityField        entityFieldDef = (EntityField)fieldToSyncInfo.fieldDef;

                    Article item = field.GetItem(_filter);

                    Article oldItem = oldField?.GetItem(_filter);

                    if (item?.Id != oldItem?.Id)
                    {
                        newArticleUpdateData.Fields.Add(new FieldData
                        {
                            Id         = field.FieldId.Value,
                            ArticleIds = item == null ? null : new[] { item.Id }
                        });

                        if (oldItem != null && entityFieldDef.DeletingMode == DeletingMode.Delete)
                        {
                            _articlesToDelete[oldItem.Id] = entityFieldDef.Content;
                        }
                    }
                }
                else if (fieldToSyncInfo.field is MultiArticleField)
                {
                    MultiArticleField oldField       = (MultiArticleField)fieldToSyncInfo.oldField;
                    MultiArticleField field          = (MultiArticleField)fieldToSyncInfo.field;
                    EntityField       entityFieldDef = (EntityField)fieldToSyncInfo.fieldDef;

                    var items = field.GetArticles(_filter).ToArray();

                    var oldItems = oldField?.GetArticles(_filter).ToArray();

                    if (items.Length != (oldItems?.Length ?? 0) || items.Any(x => oldItems.All(y => y.Id != x.Id)))
                    {
                        newArticleUpdateData.Fields.Add(new FieldData
                        {
                            Id = field.FieldId.Value, ArticleIds = items.Select(x => x.Id).ToArray()
                        });

                        if (entityFieldDef.DeletingMode == DeletingMode.Delete)
                        {
                            int[] idsToRemove = oldItems?
                                                .Where(x => items.All(y => y.Id != x.Id))
                                                .Select(x => x.Id)
                                                .ToArray() ?? new int[0];

                            foreach (int idToRemove in idsToRemove)
                            {
                                _articlesToDelete[idToRemove] = entityFieldDef.Content;
                            }
                        }
                    }
                }
            }

            if (newArticleUpdateData.Fields.Any())
            {
                _updateData.Add(newArticleUpdateData);
            }

            foreach (var fieldInfo in associationFieldsInfo
                     .Where(x => x.fieldDef.UpdatingMode == UpdatingMode.Update || x.fieldDef is ExtensionField))
            {
                Article[] oldFieldsArticles = fieldInfo.oldField == null
                    ? new Article[0]
                    : GetChildArticles(fieldInfo.oldField, _filter).ToArray();

                foreach (Article childArticle in GetChildArticles(fieldInfo.field, _filter))
                {
                    Content childArticleDef = fieldInfo.fieldDef.GetContents()
                                              .SingleOrDefault(x => x.ContentId == childArticle.ContentId);

                    if (childArticleDef == null)
                    {
                        throw new InvalidOperationException($@"There is an conflict in product definition field {fieldInfo.field.FieldId} between ContentId={childArticle.ContentId} and Articleid={childArticle.Id}");
                    }

                    Article oldChildArticle = oldFieldsArticles.SingleOrDefault(x => x.Id == childArticle.Id);

                    ProcessArticlesTree(childArticle, oldChildArticle, childArticleDef);
                }
            }
        }