public async Task <OpResult> UpsertArticle(ArticleModel article, bool importFlag = false) { var retvalue = new OpResult(); ArticleModel existingArticle = null; if (article == null) { retvalue.LogError(ARTICLE_ERROR_DATA_MUST_BE_PROVIDED); return(retvalue); } if (!importFlag && article.Guid != Guid.Empty) { existingArticle = await _articleDal.GetArticleById(article.Guid, null, null); if (existingArticle == null) { retvalue.LogError(ARTICLE_ERROR_INVALID_RECORD); } else { article.UniqueName = existingArticle.UniqueName; article.CreatedUTC = existingArticle.CreatedUTC; article.ModifiedUTC = existingArticle.ModifiedUTC; } } if (string.IsNullOrWhiteSpace(article.Name)) { retvalue.LogError(ARTICLE_ERROR_TITLE_IS_REQUIRED); } if (string.IsNullOrEmpty(article.Description)) { retvalue.LogError(ARTICLE_ERROR_DESCRIPTION_IS_REQUIRED); } if (string.IsNullOrEmpty(article.Category)) { retvalue.LogError(ARTICLE_ERROR_CATEGORY_IS_REQUIRED); } if (!string.IsNullOrEmpty(article.DefaultSection) && article.Sections != null && !article.Sections.Any(s => s.Name != null && s.Name.Equals(article.DefaultSection, StringComparison.OrdinalIgnoreCase))) { retvalue.LogError(ARTICLE_ERROR_DEFAULT_SECTION_INVALID); } if (article.Sections != null) { var counter = 0; foreach (var section in article.Sections) { counter++; if (string.IsNullOrEmpty(section.Name)) { retvalue.LogError(string.Format(SECTION_ERROR_NAME_IS_REQUIRED, counter)); } if (string.IsNullOrEmpty(section.Data)) { retvalue.LogError(string.Format(SECTION_ERROR_CONTENT_IS_REQUIRED, counter)); } } } if ((article.Sections == null || article.Sections.Count <= 0) && string.IsNullOrEmpty(article.ContentURL)) { retvalue.LogError(ARTICLE_ERROR_EITHER_URL_OR_SECTION_REQUIRED); } if (retvalue.Successful) { Dictionary <string, bool> existingUniqueNames = (await _articleDal.ListArticles(null)) .ToDictionary(a => a.UniqueName, a => true, StringComparer.OrdinalIgnoreCase); article.GenerateUniqueName(existingUniqueNames); var existingSectionGuids = new List <Guid>(); if (existingArticle != null && existingArticle.Sections != null) { existingSectionGuids = existingArticle.Sections.Select(s => s.Guid).ToList(); } _articleDal.AddTransaction(DatabaseType.PEngine, Database.OpenTransaction(DatabaseType.PEngine, false)); try { if (importFlag || article.Guid == Guid.Empty) { await _articleDal.InsertArticle(article, importFlag); } else { await _articleDal.UpdateArticle(article); } if (article.Sections != null) { var previousSectionUniqueNames = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase); foreach (var section in article.Sections) { if (!importFlag && section.Guid != Guid.Empty && !existingSectionGuids.Contains(section.Guid)) { section.Guid = Guid.Empty; } section.ArticleGuid = article.Guid; section.GenerateUniqueName(previousSectionUniqueNames); previousSectionUniqueNames.Add(section.UniqueName, true); if (importFlag || section.Guid == Guid.Empty || !existingSectionGuids.Contains(section.Guid)) { await _articleDal.InsertArticleSection(section, importFlag); } else { await _articleDal.UpdateArticleSection(section); } existingSectionGuids.Remove(section.Guid); } } foreach (var sectionGuidToDelete in existingSectionGuids) { await _articleDal.DeleteArticleSection(sectionGuidToDelete); } _articleDal.CommitTransaction(DatabaseType.PEngine); } catch (Exception ex) { _articleDal.RollBackTransaction(DatabaseType.PEngine); throw new Exception("Article Transaction Failed", ex); } } return(retvalue); }