Merge branch 'AndyButland-u4-5365' into 7.2.0

This commit is contained in:
Shannon
2014-08-25 16:47:44 +10:00
6 changed files with 324 additions and 35 deletions

View File

@@ -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
/// <param name="xml"></param>
void AddOrUpdatePreviewXml(IMedia content, Func<IMedia, XElement> xml);
/// <summary>
/// Gets paged media results
/// </summary>
/// <param name="query">Query to excute</param>
/// <param name="pageNumber">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
IEnumerable<IMedia> GetPagedResultsByQuery(IQuery<IMedia> query, int pageNumber, int pageSize, out int totalRecords,
string orderBy, Direction orderDirection, string filter = "");
}
}

View File

@@ -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
/// <summary>
/// Gets paged media results
/// </summary>
/// <param name="query">Query to excute</param>
/// <param name="pageNumber">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetPagedResultsByQuery(IQuery<IMedia> 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<IMedia>(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<IMedia> result;
var pagedResult = Database.Page<ContentVersionDto>(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<Umbraco.Core.Models.Media>()
.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<IMedia>();
}
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)
{

View File

@@ -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
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
IEnumerable<IMedia> GetChildren(int id);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageNumber">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirections">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedChildren(int id, int pageNumber, int pageSize, out int totalChildren,
string orderBy, Direction orderDirection, string filter = "");
/// <summary>
/// Gets descendants of a <see cref="IMedia"/> object by its Id
/// </summary>

View File

@@ -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
}
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageNumber">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirections">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IMedia> 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<IMedia>.Builder.Where(x => x.ParentId == id);
var medias = repository.GetPagedResultsByQuery(query, pageNumber, pageSize, out totalChildren, orderBy, orderDirection, filter);
return medias;
}
}
/// <summary>
/// Gets descendants of a <see cref="IMedia"/> object by its Id
/// </summary>

View File

@@ -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<IMedia>.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<IMedia>.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<IMedia>.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<IMedia>.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<IMedia>.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<IMedia>.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<IMedia>.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<IMedia>.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()
{

View File

@@ -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<ContentItemBasic<ContentPropertyBasic, IMedia>>(0, 0, 0);
var result = children
.Select(Mapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic, IMedia>>)
.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<ContentItemBasic<ContentPropertyBasic, IMedia>>(
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<ContentItemBasic<ContentPropertyBasic, IMedia>>(0, 0, 0);
}
var pagedResult = new PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>>(totalChildren, pageNumber, pageSize);
pagedResult.Items = children
.Select(Mapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic, IMedia>>);
return pagedResult;
}
/// <summary>