diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs
index f5823303fd..511d7ce1bc 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs
@@ -1,6 +1,9 @@
using System;
+using System.Collections.Generic;
using System.Xml.Linq;
using Umbraco.Core.Models;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
+using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -21,5 +24,18 @@ namespace Umbraco.Core.Persistence.Repositories
///
void AddOrUpdatePreviewXml(IMedia content, Func xml);
+ ///
+ /// Gets paged media results
+ ///
+ /// Query to excute
+ /// Page number
+ /// Page size
+ /// Total records query would return without paging
+ /// Field to order by
+ /// Direction to order by
+ /// Search text filter
+ /// An Enumerable list of objects
+ IEnumerable GetPagedResultsByQuery(IQuery query, int pageNumber, int pageSize, out int totalRecords,
+ string orderBy, Direction orderDirection, string filter = "");
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
index a736f16e3c..eea58c2993 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
@@ -4,11 +4,13 @@ using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
+using Umbraco.Core.Dynamics;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -397,6 +399,109 @@ namespace Umbraco.Core.Persistence.Repositories
}
#endregion
+
+ ///
+ /// Gets paged media results
+ ///
+ /// Query to excute
+ /// Page number
+ /// Page size
+ /// Total records query would return without paging
+ /// Field to order by
+ /// Direction to order by
+ /// Search text filter
+ /// An Enumerable list of objects
+ public IEnumerable GetPagedResultsByQuery(IQuery query, int pageNumber, int pageSize, out int totalRecords,
+ string orderBy, Direction orderDirection, string filter = "")
+ {
+ // Get base query
+ var sqlClause = GetBaseQuery(false);
+ var translator = new SqlTranslator(sqlClause, query);
+ var sql = translator.Translate();
+
+ // Apply filter
+ if (!string.IsNullOrEmpty(filter))
+ {
+ sql = sql.Where("umbracoNode.text LIKE @0", "%" + filter + "%");
+ }
+
+ // Apply order according to parameters
+ if (!string.IsNullOrEmpty(orderBy))
+ {
+ var orderByParams = new[] { GetDatabaseFieldNameForOrderBy(orderBy) };
+ if (orderDirection == Direction.Ascending)
+ {
+ sql = sql.OrderBy(orderByParams);
+ }
+ else
+ {
+ sql = sql.OrderByDescending(orderByParams);
+ }
+ }
+
+ // Note we can't do multi-page for several DTOs like we can multi-fetch and are doing in PerformGetByQuery,
+ // but actually given we are doing a Get on each one (again as in PerformGetByQuery), we only need the node Id.
+ // So we'll modify the SQL.
+ var modifiedSQL = sql.SQL.Replace("SELECT *", "SELECT cmsContentVersion.contentId");
+
+ // Get page of results and total count
+ IEnumerable result;
+ var pagedResult = Database.Page(pageNumber, pageSize, modifiedSQL, sql.Arguments);
+ totalRecords = Convert.ToInt32(pagedResult.TotalItems);
+ if (totalRecords > 0)
+ {
+ // Parse out node Ids and load media (we need the cast here in order to be able to call the IQueryable extension
+ // methods OrderBy or OrderByDescending)
+ var media = GetAll(pagedResult.Items
+ .DistinctBy(x => x.NodeId)
+ .Select(x => x.NodeId).ToArray())
+ .Cast()
+ .AsQueryable();
+
+ // Now we need to ensure this result is also ordered by the same order by clause
+ var orderByProperty = GetIMediaPropertyNameForOrderBy(orderBy);
+ if (orderDirection == Direction.Ascending)
+ {
+ result = media.OrderBy(orderByProperty);
+ }
+ else
+ {
+ result = media.OrderByDescending(orderByProperty);
+ }
+ }
+ else
+ {
+ result = Enumerable.Empty();
+ }
+
+ return result;
+ }
+
+ private string GetDatabaseFieldNameForOrderBy(string orderBy)
+ {
+ // Translate the passed order by field (which were originally defined for in-memory object sorting
+ // of ContentItemBasic instances) to the database field names.
+ switch (orderBy)
+ {
+ case "Name":
+ return "umbracoNode.text";
+ default:
+ return "umbracoNode.sortOrder";
+ }
+ }
+
+ private string GetIMediaPropertyNameForOrderBy(string orderBy)
+ {
+ // Translate the passed order by field (which were originally defined for in-memory object sorting
+ // of ContentItemBasic instances) to the IMedia property names.
+ switch (orderBy)
+ {
+ case "Name":
+ return "Name";
+ default:
+ return "SortOrder";
+ }
+ }
private string EnsureUniqueNodeName(int parentId, string nodeName, int id = 0)
{
diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs
index a457f69502..9916b77905 100644
--- a/src/Umbraco.Core/Services/IMediaService.cs
+++ b/src/Umbraco.Core/Services/IMediaService.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Services
{
@@ -61,6 +62,20 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
IEnumerable GetChildren(int id);
+ ///
+ /// Gets a collection of objects by Parent Id
+ ///
+ /// Id of the Parent to retrieve Children from
+ /// Page number
+ /// Page size
+ /// Total records query would return without paging
+ /// Field to order by
+ /// Direction to order by
+ /// Search text filter
+ /// An Enumerable list of objects
+ IEnumerable GetPagedChildren(int id, int pageNumber, int pageSize, out int totalChildren,
+ string orderBy, Direction orderDirection, string filter = "");
+
///
/// Gets descendants of a object by its Id
///
diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs
index 518be0ef07..e4270253d0 100644
--- a/src/Umbraco.Core/Services/MediaService.cs
+++ b/src/Umbraco.Core/Services/MediaService.cs
@@ -10,6 +10,7 @@ using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -394,6 +395,31 @@ namespace Umbraco.Core.Services
}
}
+ ///
+ /// Gets a collection of objects by Parent Id
+ ///
+ /// Id of the Parent to retrieve Children from
+ /// Page number
+ /// Page size
+ /// Total records query would return without paging
+ /// Field to order by
+ /// Direction to order by
+ /// Search text filter
+ /// An Enumerable list of objects
+ public IEnumerable GetPagedChildren(int id, int pageNumber, int pageSize, out int totalChildren,
+ string orderBy, Direction orderDirection, string filter = "")
+ {
+ Mandate.ParameterCondition(pageNumber > 0, "pageSize");
+ Mandate.ParameterCondition(pageSize > 0, "pageSize");
+ using (var repository = _repositoryFactory.CreateMediaRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.ParentId == id);
+ var medias = repository.GetPagedResultsByQuery(query, pageNumber, pageSize, out totalChildren, orderBy, orderDirection, filter);
+
+ return medias;
+ }
+ }
+
///
/// Gets descendants of a object by its Id
///
diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs
index 8f31023bdf..95890bdf8b 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs
@@ -14,6 +14,7 @@ using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
using umbraco.editorControls.tinyMCE3;
using umbraco.interfaces;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Tests.Persistence.Repositories
{
@@ -240,7 +241,6 @@ namespace Umbraco.Tests.Persistence.Repositories
MediaTypeRepository mediaTypeRepository;
using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
{
-
// Act
var query = Query.Builder.Where(x => x.Level == 2);
var result = repository.GetByQuery(query);
@@ -250,6 +250,153 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
+ [Test]
+ public void Can_Perform_GetPagedResultsByQuery_ForFirstPage_On_MediaRepository()
+ {
+ // Arrange
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ MediaTypeRepository mediaTypeRepository;
+ using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
+ {
+ // Act
+ var query = Query.Builder.Where(x => x.Level == 2);
+ int totalRecords;
+ var result = repository.GetPagedResultsByQuery(query, 1, 1, out totalRecords, "SortOrder", Direction.Ascending);
+
+ // Assert
+ Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
+ Assert.That(result.Count(), Is.EqualTo(1));
+ Assert.That(result.First().Name, Is.EqualTo("Test Image"));
+ }
+ }
+
+ [Test]
+ public void Can_Perform_GetPagedResultsByQuery_ForSecondPage_On_MediaRepository()
+ {
+ // Arrange
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ MediaTypeRepository mediaTypeRepository;
+ using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
+ {
+ // Act
+ var query = Query.Builder.Where(x => x.Level == 2);
+ int totalRecords;
+ var result = repository.GetPagedResultsByQuery(query, 2, 1, out totalRecords, "SortOrder", Direction.Ascending);
+
+ // Assert
+ Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
+ Assert.That(result.Count(), Is.EqualTo(1));
+ Assert.That(result.First().Name, Is.EqualTo("Test File"));
+ }
+ }
+
+ [Test]
+ public void Can_Perform_GetPagedResultsByQuery_WithSinglePage_On_MediaRepository()
+ {
+ // Arrange
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ MediaTypeRepository mediaTypeRepository;
+ using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
+ {
+ // Act
+ var query = Query.Builder.Where(x => x.Level == 2);
+ int totalRecords;
+ var result = repository.GetPagedResultsByQuery(query, 1, 2, out totalRecords, "SortOrder", Direction.Ascending);
+
+ // Assert
+ Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
+ Assert.That(result.Count(), Is.EqualTo(2));
+ Assert.That(result.First().Name, Is.EqualTo("Test Image"));
+ }
+ }
+
+ [Test]
+ public void Can_Perform_GetPagedResultsByQuery_WithDescendingOrder_On_MediaRepository()
+ {
+ // Arrange
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ MediaTypeRepository mediaTypeRepository;
+ using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
+ {
+ // Act
+ var query = Query.Builder.Where(x => x.Level == 2);
+ int totalRecords;
+ var result = repository.GetPagedResultsByQuery(query, 1, 1, out totalRecords, "SortOrder", Direction.Descending);
+
+ // Assert
+ Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
+ Assert.That(result.Count(), Is.EqualTo(1));
+ Assert.That(result.First().Name, Is.EqualTo("Test File"));
+ }
+ }
+
+ [Test]
+ public void Can_Perform_GetPagedResultsByQuery_WitAlternateOrder_On_MediaRepository()
+ {
+ // Arrange
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ MediaTypeRepository mediaTypeRepository;
+ using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
+ {
+ // Act
+ var query = Query.Builder.Where(x => x.Level == 2);
+ int totalRecords;
+ var result = repository.GetPagedResultsByQuery(query, 1, 1, out totalRecords, "Name", Direction.Ascending);
+
+ // Assert
+ Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
+ Assert.That(result.Count(), Is.EqualTo(1));
+ Assert.That(result.First().Name, Is.EqualTo("Test File"));
+ }
+ }
+
+ [Test]
+ public void Can_Perform_GetPagedResultsByQuery_WithFilterMatchingSome_On_MediaRepository()
+ {
+ // Arrange
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ MediaTypeRepository mediaTypeRepository;
+ using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
+ {
+ // Act
+ var query = Query.Builder.Where(x => x.Level == 2);
+ int totalRecords;
+ var result = repository.GetPagedResultsByQuery(query, 1, 1, out totalRecords, "SortOrder", Direction.Ascending, "File");
+
+ // Assert
+ Assert.That(totalRecords, Is.EqualTo(1));
+ Assert.That(result.Count(), Is.EqualTo(1));
+ Assert.That(result.First().Name, Is.EqualTo("Test File"));
+ }
+ }
+
+ [Test]
+ public void Can_Perform_GetPagedResultsByQuery_WithFilterMatchingAll_On_MediaRepository()
+ {
+ // Arrange
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ MediaTypeRepository mediaTypeRepository;
+ using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
+ {
+ // Act
+ var query = Query.Builder.Where(x => x.Level == 2);
+ int totalRecords;
+ var result = repository.GetPagedResultsByQuery(query, 1, 1, out totalRecords, "SortOrder", Direction.Ascending, "Test");
+
+ // Assert
+ Assert.That(totalRecords, Is.EqualTo(2));
+ Assert.That(result.Count(), Is.EqualTo(1));
+ Assert.That(result.First().Name, Is.EqualTo("Test Image"));
+ }
+ }
+
[Test]
public void Can_Perform_GetAll_By_Param_Ids_On_MediaRepository()
{
diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs
index 3ea57a7967..84eedb000c 100644
--- a/src/Umbraco.Web/Editors/MediaController.cs
+++ b/src/Umbraco.Web/Editors/MediaController.cs
@@ -138,48 +138,28 @@ namespace Umbraco.Web.Editors
Direction orderDirection = Direction.Ascending,
string filter = "")
{
- //TODO: This will be horribly inefficient for paging! This is because our datasource/repository
- // doesn't support paging at the SQL level... and it'll be pretty interesting to try to make that work.
-
- var children = Services.MediaService.GetChildren(id).ToArray();
- var totalChildren = children.Length;
-
- if (totalChildren == 0)
- return new PagedResult>(0, 0, 0);
-
- var result = children
- .Select(Mapper.Map>)
- .AsQueryable();
-
- //TODO: This is a rudimentry filter - should use the logic found in the EntityService filter (dynamic linq) instead
- if (!string.IsNullOrEmpty(filter))
- {
- filter = filter.ToLower();
- result = result.Where(x => x.Name.InvariantContains(filter));
- }
-
- var orderedResult = orderDirection == Direction.Ascending
- ? result.OrderBy(orderBy)
- : result.OrderByDescending(orderBy);
-
- var pagedResult = new PagedResult>(
- totalChildren,
- pageNumber,
- pageSize);
-
+ int totalChildren;
+ IMedia[] children;
if (pageNumber > 0 && pageSize > 0)
{
- pagedResult.Items = orderedResult
- .Skip(pagedResult.SkipSize)
- .Take(pageSize);
+ children = Services.MediaService.GetPagedChildren(id, pageNumber, pageSize, out totalChildren, orderBy, orderDirection, filter).ToArray();
}
else
{
- pagedResult.Items = orderedResult;
+ children = Services.MediaService.GetChildren(id).ToArray();
+ totalChildren = children.Length;
}
- return pagedResult;
+ if (totalChildren == 0)
+ {
+ return new PagedResult>(0, 0, 0);
+ }
+ var pagedResult = new PagedResult>(totalChildren, pageNumber, pageSize);
+ pagedResult.Items = children
+ .Select(Mapper.Map>);
+
+ return pagedResult;
}
///