2015-10-29 37 views
0

我有一個評論式結構,用戶能夠進行回覆的文章。 (一篇文章可以有很多討論回覆)。當用戶添加回復時,我希望父項文章的最後更新日期也發生變化,以便在從前端查看時,文章位於列表的頂部,表明它已具有最近的活動。爲了達到這個目的,評論是通過一個自定義控制器添加的,然後我使用ContentService發佈事件來更新父項,儘管我發現我的事件是一個瓶頸,需要長達六秒的時間才能運行一把umbraco發佈的事件表現

public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) 
{ 
    ContentService.Published += ContentServicePublished; 
} 

private void ContentServicePublished(IPublishingStrategy sender, PublishEventArgs<IContent> e) 
{ 
    foreach (var node in e.PublishedEntities) 
    { 
     //Handle updating the parent nodes last edited date to address ordering 
     if (node.ContentType.Alias == "DiscussionReply") 
     { 
      var contentService = new Umbraco.Core.Services.ContentService(); 
      var parentNode = contentService.GetById(node.ParentId); 
      int intSiblings = parentNode.Children().Count() + 1; 

      if(parentNode.HasProperty("siblings")) 
      { 
       parentNode.SetValue("siblings", intSiblings); 
       contentService.SaveAndPublishWithStatus(parentNode, 0, false); 
      } 
     } 
    } 
} 

有什麼明顯的與此代碼可能會引發性能問題?

非常感謝,

+2

我的猜測:你不應該爲每個節點創建一個新的contentService的,應在foreach之前只有一次完成... –

回答

1

您應該使用服務辛格爾頓用於訪問各種服務,包括ContentService

一種方式這樣做是爲了訪問服務上ApplicationContext.Current像這樣:

var contentService = ApplicationContext.Current.Services.ContentService; 

但是,您的瓶頸將是在檢索父節點,它是需要到數據庫中多次調用屬性。最重要的是,你在這裏獲取父母的孩子:

int intSiblings = parentNode.Children().Count() + 1; 

更好的解決方案是使用PublishedContent緩存這完全不打數據庫,並提供顯著卓越的性能。

如果您使用的是SurfaceController使用它的Umbraco屬性(你也有Services接入以及):

// After you've published the comment node: 
var commentNode = Umbraco.TypedContent(commentNodeId); 

// We already know this is a DiscussionReply node, no need to check. 

int intSiblings = commentNode.Parent.Children.Count() + 1; 

if (commentNode.Parent.HasProperty("siblings")) 
{ 
    // It's only now that we really need to grab the parent node from the ContentService so we can update it. 
    var parentNode = Services.ContentService.GetById(commentNode.ParentId); 
    parentNode.SetValue("siblings", intSiblings); 
    contentService.SaveAndPublishWithStatus(parentNode, 0, false); 
} 

如果您正在實施基於UmbracoApiController一個的WebAPI那麼同樣UmbracoServices屬性也可以在那裏使用。

+0

非常感謝您評估代碼,您的建議非常好,有助於解釋我遇到的問題。無論如何,我可以使用ContentService.Published事件,而不是添加到我的表面控制器?我之所以認爲發佈的事件是因爲我可以設置這個屬性,即使在Umbraco管理區中添加了回覆,而絕對是通過我的表單/表面控制器動作 – spocky

+0

;你仍然可以使用PublishedContent緩存來評估你的條件 - 你可能需要實例化UmbracoHelper:'new UmbracoHelper(UmbracoContext.Current);'應該這樣做。 –

0

我使用一把umbraco 7.3.4,這裏是我的解決方案:

// Create a list of objects to be created or updated. 
var newContentList = new List<MyCustomModel>() { 
new MyCustomModel {Id: 1, Name: "Document 1", Attribute1: ...}, 
new MyCustomModel {Id: 2, Name: "Document 2", Attribute1: ...}, 
new MyCustomModel {Id: 3, Name: "Document 3", Attribute1: ...} 
}; 

// Get old content from cache 
var oldContentAsIPublishedContentList = (new UmbracoHelper(UmbracoContext.Current)).TypedContent(ParentId).Descendants("YourContentType").ToList(); 

// Get only modified content items 
var modifiedItemIds = from x in oldContentAsIPublishedContentList 
          from y in newContentList 
          where x.Id == y.Id 
          && (x.Name != y.Name || x.Attribute1 != y.Attribute1) 
          select x.Id; 

// Get modified items as an IContent list. 
var oldContentAsIContentList = ApplicationContext.Services.ContentService.GetByIds(modifiedItemIds).ToList(); 

// Create final content list. 
var finalContentList= new List<IContent>(); 

// Update or insert items 
foreach(var item in newContentList) { 
    // For each new content item, find an old IContent by the ID 
    // If the old IContent is found and the values are modified, add it to the finalContentList 
    // Otherwise, create a new instance using the API. 
    IContent content = oldContentAsIContentList.FirstOrDefault(x => x.Id == item.Id) ?? ApplicationContext.Services.ContentService.CreateContent(item.Name, ParentId, "YourContentType"); 

    // Update content 
    content.Name = item.Name; 
    content.SetValue("Attribute1", item.Attribute1);   
    finalContentList.Add(content); 

    // The following code is required 
    content.ChangePublishedState(PublishedState.Published); 
    content.SortOrder = 1; 
} 

// if the finalContentList has some items, call the Sort method to commit and publish the changes 
ApplicationContext.Services.ContentService.Sort(finalContentList);