diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
index 755fc5f04a..001705ebb9 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
@@ -449,7 +449,15 @@ namespace Umbraco.Core.Persistence.Repositories
foreach (var dto in dtos)
{
- yield return CreateContentFromDto(dto, dto.VersionId);
+ var fromCache = TryGetFromCache(dto.NodeId);
+ if (fromCache.Success)
+ {
+ yield return fromCache.Result;
+ }
+ else
+ {
+ yield return CreateContentFromDto(dto, dto.VersionId);
+ }
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs
index cbd8b9d252..3967aef5e6 100644
--- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs
@@ -85,11 +85,10 @@ namespace Umbraco.Core.Persistence.Repositories
///
public TEntity Get(TId id)
{
- Guid key = id is int ? ConvertIdToGuid(id) : ConvertStringIdToGuid(id.ToString());
- var rEntity = _cache.GetById(typeof(TEntity), key);
- if (rEntity != null)
+ var fromCache = TryGetFromCache(id);
+ if (fromCache.Success)
{
- return (TEntity)rEntity;
+ return fromCache.Result;
}
var entity = PerformGet(id);
@@ -112,6 +111,17 @@ namespace Umbraco.Core.Persistence.Repositories
return entity;
}
+ protected Attempt TryGetFromCache(TId id)
+ {
+ Guid key = id is int ? ConvertIdToGuid(id) : ConvertStringIdToGuid(id.ToString());
+ var rEntity = _cache.GetById(typeof(TEntity), key);
+ if (rEntity != null)
+ {
+ return new Attempt(true, (TEntity) rEntity);
+ }
+ return Attempt.False;
+ }
+
protected abstract IEnumerable PerformGetAll(params TId[] ids);
///
/// Gets all entities of type TEntity or a list according to the passed in Ids
@@ -173,14 +183,12 @@ namespace Umbraco.Core.Persistence.Repositories
///
public bool Exists(TId id)
{
- Guid key = id is int ? ConvertIdToGuid(id) : ConvertStringIdToGuid(id.ToString());
- var rEntity = _cache.GetById(typeof(TEntity), key);
- if (rEntity != null)
+ var fromCache = TryGetFromCache(id);
+ if (fromCache.Success)
{
return true;
}
-
- return PerformExists(id);
+ return PerformExists(id);
}
protected abstract int PerformCount(IQuery query);
diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs
index 83ff46d958..b47879bda1 100644
--- a/src/Umbraco.Core/Services/ContentService.cs
+++ b/src/Umbraco.Core/Services/ContentService.cs
@@ -13,6 +13,7 @@ using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Querying;
+using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Publishing;
@@ -250,6 +251,17 @@ namespace Umbraco.Core.Services
}
}
+ internal IEnumerable GetPublishedContentOfContentType(int id)
+ {
+ using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.ContentTypeId == id);
+ var contents = repository.GetByPublishedVersion(query);
+
+ return contents;
+ }
+ }
+
///
/// Gets a collection of objects by Level
///
@@ -431,6 +443,19 @@ namespace Umbraco.Core.Services
}
}
+ ///
+ /// Gets all published content items
+ ///
+ ///
+ internal IEnumerable GetAllPublished()
+ {
+ using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.Trashed == false);
+ return repository.GetByPublishedVersion(query);
+ }
+ }
+
///
/// Gets a collection of objects, which has an expiration date less than or equal to today.
///
@@ -1359,23 +1384,13 @@ namespace Umbraco.Core.Services
uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN
(SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml
INNER JOIN cmsDocument ON cmsContentXml.nodeId = cmsDocument.nodeId)");
-
- //get all content items that are published
- // Consider creating a Path query instead of recursive method:
- // var query = Query.Builder.Where(x => x.Path.StartsWith("-1"));
- var rootContent = GetRootContent();
- foreach (var content in rootContent.Where(content => content.Published))
- {
- list.Add(content);
- list.AddRange(GetPublishedDescendants(content));
- }
+
+ list.AddRange(GetAllPublished());
}
else
{
foreach (var id in contentTypeIds)
{
-
-
//first we'll clear out the data from the cmsContentXml table for this type
uow.Database.Execute(@"delete from cmsContentXml where nodeId in
(select cmsDocument.nodeId from cmsDocument
@@ -1383,7 +1398,7 @@ namespace Umbraco.Core.Services
where published = 1 and contentType = @contentTypeId)", new {contentTypeId = id});
//now get all published content objects of this type and add to the list
- list.AddRange(GetContentOfContentType(id).Where(content => content.Published));
+ list.AddRange(GetPublishedContentOfContentType(id));
}
}
diff --git a/src/Umbraco.Tests/Services/PerformanceTests.cs b/src/Umbraco.Tests/Services/PerformanceTests.cs
index 892cc6f84d..e49d2a1da3 100644
--- a/src/Umbraco.Tests/Services/PerformanceTests.cs
+++ b/src/Umbraco.Tests/Services/PerformanceTests.cs
@@ -11,6 +11,7 @@ using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -66,6 +67,90 @@ namespace Umbraco.Tests.Services
base.TearDown();
}
+ [Test]
+ public void Get_All_Published_Content()
+ {
+ var result = PrimeDbWithLotsOfContent();
+ var contentSvc = (ContentService) ServiceContext.ContentService;
+
+ var countOfPublished = result.Count(x => x.Published);
+ var contentTypeId = result.First().ContentTypeId;
+
+ using (DisposableTimer.DebugDuration("Getting published content normally"))
+ {
+ //do this 10x!
+ for (var i = 0; i < 10; i++)
+ {
+ //clear the cache to make this test valid
+ RuntimeCacheProvider.Current.Clear();
+
+ var published = new List();
+ //get all content items that are published
+ var rootContent = contentSvc.GetRootContent();
+ foreach (var content in rootContent.Where(content => content.Published))
+ {
+ published.Add(content);
+ published.AddRange(contentSvc.GetPublishedDescendants(content));
+ }
+ Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
+ }
+
+ }
+
+ using (DisposableTimer.DebugDuration("Getting published content optimized"))
+ {
+
+ //do this 10x!
+ for (var i = 0; i < 10; i++)
+ {
+ //clear the cache to make this test valid
+ RuntimeCacheProvider.Current.Clear();
+
+ //get all content items that are published
+ var published = contentSvc.GetAllPublished();
+
+ Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
+ }
+ }
+ }
+
+ [Test]
+ public void Get_All_Published_Content_Of_Type()
+ {
+ var result = PrimeDbWithLotsOfContent();
+ var contentSvc = (ContentService)ServiceContext.ContentService;
+
+ var countOfPublished = result.Count(x => x.Published);
+ var contentTypeId = result.First().ContentTypeId;
+
+ using (DisposableTimer.DebugDuration("Getting published content of type normally"))
+ {
+ //do this 10x!
+ for (var i = 0; i < 10; i++)
+ {
+ //clear the cache to make this test valid
+ RuntimeCacheProvider.Current.Clear();
+ //get all content items that are published of this type
+ var published = contentSvc.GetContentOfContentType(contentTypeId).Where(content => content.Published);
+ Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
+ }
+ }
+
+ using (DisposableTimer.DebugDuration("Getting published content of type optimized"))
+ {
+
+ //do this 10x!
+ for (var i = 0; i < 10; i++)
+ {
+ //clear the cache to make this test valid
+ RuntimeCacheProvider.Current.Clear();
+ //get all content items that are published of this type
+ var published = contentSvc.GetPublishedContentOfContentType(contentTypeId);
+ Assert.AreEqual(countOfPublished, published.Count(x => x.ContentTypeId == contentTypeId));
+ }
+ }
+ }
+
[Test]
public void Truncate_Insert_Vs_Update_Insert()
{
@@ -130,6 +215,51 @@ namespace Umbraco.Tests.Services
}
+ private IEnumerable PrimeDbWithLotsOfContent()
+ {
+ var contentType1 = MockedContentTypes.CreateSimpleContentType();
+ contentType1.AllowedAsRoot = true;
+ ServiceContext.ContentTypeService.Save(contentType1);
+ contentType1.AllowedContentTypes = new List
+ {
+ new ContentTypeSort
+ {
+ Alias = contentType1.Alias,
+ Id = new Lazy(() => contentType1.Id),
+ SortOrder = 0
+ }
+ };
+ var result = new List();
+ ServiceContext.ContentTypeService.Save(contentType1);
+ IContent lastParent = MockedContent.CreateSimpleContent(contentType1);
+ ServiceContext.ContentService.SaveAndPublish(lastParent);
+ result.Add(lastParent);
+ //create 20 deep
+ for (var i = 0; i < 20; i++)
+ {
+ //for each level, create 20
+ IContent content = null;
+ for (var j = 1; j <= 10; j++)
+ {
+ content = MockedContent.CreateSimpleContent(contentType1, "Name" + j, lastParent);
+ //only publish evens
+ if (j % 2 == 0)
+ {
+ ServiceContext.ContentService.SaveAndPublish(content);
+ }
+ else
+ {
+ ServiceContext.ContentService.Save(content);
+ }
+ result.Add(content);
+ }
+
+ //assign the last one as the next parent
+ lastParent = content;
+ }
+ return result;
+ }
+
private IEnumerable PrimeDbWithLotsOfContentXmlRecords(Guid customObjectType)
{
var nodes = new List();