diff --git a/src/Umbraco.Core/Persistence/Repositories/IContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IContentRepository.cs
index fea0a61589..f7341d112b 100644
--- a/src/Umbraco.Core/Persistence/Repositories/IContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/IContentRepository.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
+using Umbraco.Core.Services;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -67,7 +68,8 @@ namespace Umbraco.Core.Persistence.Repositories
///
/// Gets paged content items.
///
+ /// Here, can be null but cannot.
IEnumerable GetPage(IQuery query, long pageIndex, int pageSize, out long totalRecords,
- string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter = null);
+ IQuery filter, Ordering ordering);
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs
index 2e0139aa30..4e68262e55 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs
@@ -232,16 +232,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
#endregion
- public abstract IEnumerable GetPage(IQuery query, long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter = null);
-
- // sql: the main sql
- // filterSql: a filtering ? fixme different from v7?
- // orderBy: the name of an ordering field
- // orderDirection: direction for orderBy
- // orderBySystemField: whether orderBy is a system field or a custom field (property value)
- private Sql PrepareSqlForPage(Sql sql, Sql filterSql, string orderBy, Direction orderDirection, bool orderBySystemField)
+ private Sql PreparePageSql(Sql sql, Sql filterSql, Ordering ordering)
{
- if (filterSql == null && string.IsNullOrEmpty(orderBy)) return sql;
+ // non-filtering, non-ordering = nothing to do
+ if (filterSql == null && ordering.IsEmpty) return sql;
// preserve original
var psql = new Sql(sql.SqlContext, sql.SQL, sql.Arguments);
@@ -251,25 +245,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
psql.Append(filterSql);
// non-sorting, we're done
- if (string.IsNullOrEmpty(orderBy))
+ if (ordering.IsEmpty)
return psql;
- // else apply sort
- var dbfield = orderBySystemField
- ? GetOrderBySystemField(ref psql, orderBy)
- : GetOrderByNonSystemField(ref psql, orderBy);
-
- if (orderDirection == Direction.Ascending)
- psql.OrderBy(dbfield);
- else
- psql.OrderByDescending(dbfield);
+ // else apply ordering
+ ApplyOrdering(ref psql, ordering);
// no matter what we always MUST order the result also by umbracoNode.id to ensure that all records being ordered by are unique.
// if we do not do this then we end up with issues where we are ordering by a field that has duplicate values (i.e. the 'text' column
// is empty for many nodes) - see: http://issues.umbraco.org/issue/U4-8831
- dbfield = GetDatabaseFieldNameForOrderBy("umbracoNode", "id");
- if (orderBySystemField == false || orderBy.InvariantEquals(dbfield) == false)
+ var dbfield = GetQuotedFieldName("umbracoNode", "id");
+ if (ordering.IsCustomField || !ordering.OrderBy.InvariantEquals("id"))
{
// get alias, if aliased
var matches = SqlContext.SqlSyntax.AliasRegex.Matches(sql.SQL);
@@ -282,43 +269,92 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// create prepared sql
// ensure it's single-line as NPoco PagingHelper has issues with multi-lines
- psql = new Sql(psql.SqlContext, psql.SQL.ToSingleLine(), psql.Arguments);
+ psql = Sql(psql.SQL.ToSingleLine(), psql.Arguments);
return psql;
}
- private string GetOrderBySystemField(ref Sql sql, string orderBy)
+ private void ApplyOrdering(ref Sql sql, Ordering ordering)
{
- // get the database field eg "[table].[column]"
- var dbfield = GetDatabaseFieldNameForOrderBy(orderBy);
+ if (sql == null) throw new ArgumentNullException(nameof(sql));
+ if (ordering == null) throw new ArgumentNullException(nameof(ordering));
- // for SqlServer pagination to work, the "order by" field needs to be the alias eg if
- // the select statement has "umbracoNode.text AS NodeDto__Text" then the order field needs
- // to be "NodeDto__Text" and NOT "umbracoNode.text".
- // not sure about SqlCE nor MySql, so better do it too. initially thought about patching
- // NPoco but that would be expensive and not 100% possible, so better give NPoco proper
- // queries to begin with.
- // thought about maintaining a map of columns-to-aliases in the sql context but that would
- // be expensive and most of the time, useless. so instead we parse the SQL looking for the
- // alias. somewhat expensive too but nothing's free.
+ var orderBy = ordering.IsCustomField
+ ? ApplyCustomOrdering(ref sql, ordering)
+ : ApplySystemOrdering(ref sql, ordering);
- // note: ContentTypeAlias is not properly managed because it's not part of the query to begin with!
-
- // get alias, if aliased
- var matches = SqlContext.SqlSyntax.AliasRegex.Matches(sql.SQL);
- var match = matches.Cast().FirstOrDefault(m => m.Groups[1].Value.InvariantEquals(dbfield));
- if (match != null) dbfield = match.Groups[2].Value;
-
- return dbfield;
+ if (ordering.Direction == Direction.Ascending)
+ sql.OrderBy(orderBy);
+ else
+ sql.OrderByDescending(orderBy);
}
- private string GetOrderByNonSystemField(ref Sql sql, string orderBy)
+ protected virtual string ApplySystemOrdering(ref Sql sql, Ordering ordering)
+ {
+ // id is invariant
+ if (ordering.OrderBy.InvariantEquals("id"))
+ return SqlSyntax.GetFieldName(x => x.NodeId);
+
+ // sort order is invariant
+ if (ordering.OrderBy.InvariantEquals("sortOrder"))
+ return SqlSyntax.GetFieldName(x => x.SortOrder);
+
+ // path is invariant
+ if (ordering.OrderBy.InvariantEquals("path"))
+ return SqlSyntax.GetFieldName(x => x.Path);
+
+ // note: 'owner' is the user who created the item as a whole,
+ // we don't have an 'owner' per culture (should we?)
+ if (ordering.OrderBy.InvariantEquals("owner"))
+ {
+ var joins = Sql()
+ .InnerJoin("ownerUser").On((node, user) => node.UserId == user.Id, aliasRight: "ownerUser");
+
+ sql = InsertJoins(sql, joins);
+
+ return SqlSyntax.GetFieldName(x => x.UserName, "ownerUser");
+ }
+
+ // note: each version culture variation has a date too,
+ // maybe we would want to use it instead?
+ if (ordering.OrderBy.InvariantEquals("versionDate") || ordering.OrderBy.InvariantEquals("updateDate"))
+ return SqlSyntax.GetFieldName(x => x.VersionDate);
+
+ // create date is invariant (we don't keep each culture's creation date)
+ if (ordering.OrderBy.InvariantEquals("createDate"))
+ return SqlSyntax.GetFieldName(x => x.CreateDate);
+
+ // name is variant
+ if (ordering.OrderBy.InvariantEquals("name"))
+ {
+ // no culture = can only work on the invariant name
+ if (ordering.Culture.IsNullOrWhiteSpace())
+ return SqlSyntax.GetFieldName(x => x.Text);
+
+ // culture = must work on variant name ?? invariant name
+ // insert proper join and return coalesced ordering field
+
+ var joins = Sql()
+ .LeftJoin(nested =>
+ nested.InnerJoin("lang").On((ccv, lang) => ccv.LanguageId == lang.Id && lang.IsoCode == ordering.Culture, "ccv", "lang"), "ccv")
+ .On((version, ccv) => version.Id == ccv.VersionId, aliasRight: "ccv");
+
+ sql = InsertJoins(sql, joins);
+
+ return SqlContext.Visit((ccv, node) => ccv.Name ?? node.Text, "ccv").Sql;
+ }
+
+ // previously, we'd accept anything and just sanitize it - not anymore
+ throw new NotSupportedException($"Ordering by {ordering.OrderBy} not supported.");
+ }
+
+ private string ApplyCustomOrdering(ref Sql sql, Ordering ordering)
{
// sorting by a custom field, so set-up sub-query for ORDER BY clause to pull through value
// from 'current' content version for the given order by field
var sortedInt = string.Format(SqlContext.SqlSyntax.ConvertIntegerToOrderableString, "intValue");
+ var sortedDecimal = string.Format(SqlContext.SqlSyntax.ConvertDecimalToOrderableString, "decimalValue");
var sortedDate = string.Format(SqlContext.SqlSyntax.ConvertDateToOrderableString, "dateValue");
var sortedString = "COALESCE(varcharValue,'')"; // assuming COALESCE is ok for all syntaxes
- var sortedDecimal = string.Format(SqlContext.SqlSyntax.ConvertDecimalToOrderableString, "decimalValue");
// needs to be an outer join since there's no guarantee that any of the nodes have values for this property
var innerSql = Sql().Select($@"CASE
@@ -329,49 +365,59 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
END AS customPropVal,
cver.nodeId AS customPropNodeId")
.From("cver")
- .InnerJoin("opdata").On((left, right) => left.Id == right.Id, "cver", "opdata")
- .InnerJoin("optype").On((left, right) => left.PropertyTypeId == right.Id, "opdata", "optype")
+ .InnerJoin("opdata")
+ .On((version, pdata) => version.Id == pdata.VersionId, "cver", "opdata")
+ .InnerJoin("optype").On((pdata, ptype) => pdata.PropertyTypeId == ptype.Id, "opdata", "optype")
+ .LeftJoin().On((pdata, lang) => pdata.LanguageId == lang.Id, "opdata")
.Where(x => x.Current, "cver") // always query on current (edit) values
- .Where(x => x.Alias == "", "optype");
+ .Where(x => x.Alias == ordering.OrderBy, "optype")
+ .Where((opdata, lang) => opdata.LanguageId == null || lang.IsoCode == ordering.Culture, "opdata");
- // @0 is for x.Current ie 'true' = 1
- // @1 is for x.Alias
- var innerSqlString = innerSql.SQL.Replace("@0", "1").Replace("@1", "@" + sql.Arguments.Length);
+ // merge arguments
+ var argsList = sql.Arguments.ToList();
+ var innerSqlString = ParameterHelper.ProcessParams(innerSql.SQL, innerSql.Arguments, argsList);
+
+ // create the outer join complete sql fragment
var outerJoinTempTable = $@"LEFT OUTER JOIN ({innerSqlString}) AS customPropData
ON customPropData.customPropNodeId = {Constants.DatabaseSchema.Tables.Node}.id "; // trailing space is important!
- // insert this just above the last WHERE
- var pos = sql.SQL.InvariantIndexOf("WHERE");
- if (pos < 0) throw new Exception("Oops, WHERE not found.");
- var newSql = sql.SQL.Insert(pos, outerJoinTempTable);
+ // insert this just above the first WHERE
+ var newSql = InsertBefore(sql.SQL, "WHERE", outerJoinTempTable);
- var newArgs = sql.Arguments.ToList();
- newArgs.Add(orderBy);
+ // insert the SQL selected field, too, before the first FROM else ordering cannot work
+ newSql = InsertBefore(newSql, "FROM", ", customPropData.customPropVal "); // trailing space is important!
- // insert the SQL selected field, too, else ordering cannot work
- if (sql.SQL.StartsWith("SELECT ") == false) throw new Exception("Oops: SELECT not found.");
- newSql = newSql.Insert("SELECT ".Length, "customPropData.customPropVal, ");
-
- sql = new Sql(sql.SqlContext, newSql, newArgs.ToArray());
+ // create the new sql
+ sql = Sql(newSql, argsList.ToArray());
// and order by the custom field
+ // this original code means that an ascending sort would first expose all NULL values, ie items without a value
return "customPropData.customPropVal";
+ // this better (?) code ensures that items without a value always come last (ie both in asc- and desc-ending sorts)
+ // not enabled yet - should we?
+ //return "(CASE WHEN customPropData.customPropVal IS NULL THEN 1 ELSE 0 END), customPropData.customPropVal";
}
+ public abstract IEnumerable GetPage(IQuery query,
+ long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter,
+ Ordering ordering);
+
+ // here, filter can be null and ordering cannot
protected IEnumerable GetPage(IQuery query,
long pageIndex, int pageSize, out long totalRecords,
Func, IEnumerable> mapDtos,
- string orderBy, Direction orderDirection, bool orderBySystemField,
- Sql filterSql = null) // fixme filter is different on v7?
+ Sql filter,
+ Ordering ordering)
{
- if (orderBy == null) throw new ArgumentNullException(nameof(orderBy));
+ if (ordering == null) throw new ArgumentNullException(nameof(ordering));
// start with base query, and apply the supplied IQuery
- if (query == null) query = AmbientScope.SqlContext.Query();
+ if (query == null) query = Query();
var sql = new SqlTranslator(GetBaseQuery(QueryType.Many), query).Translate();
// sort and filter
- sql = PrepareSqlForPage(sql, filterSql, orderBy, orderDirection, orderBySystemField);
+ sql = PreparePageSql(sql, filter, ordering);
// get a page of DTOs and the total count
var pagedResult = Database.Page(pageIndex + 1, pageSize, sql);
@@ -498,36 +544,30 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return result;
}
- protected virtual string GetDatabaseFieldNameForOrderBy(string orderBy)
+ protected string InsertBefore(string s, string atToken, string insert)
{
- // translate the supplied "order by" field, which were originally defined for in-memory
- // object sorting of ContentItemBasic instance, to the actual database field names.
-
- switch (orderBy.ToUpperInvariant())
- {
- case "VERSIONDATE":
- case "UPDATEDATE":
- return GetDatabaseFieldNameForOrderBy(Constants.DatabaseSchema.Tables.ContentVersion, "versionDate");
- case "CREATEDATE":
- return GetDatabaseFieldNameForOrderBy("umbracoNode", "createDate");
- case "NAME":
- return GetDatabaseFieldNameForOrderBy("umbracoNode", "text");
- case "PUBLISHED":
- return GetDatabaseFieldNameForOrderBy(Constants.DatabaseSchema.Tables.Document, "published");
- case "OWNER":
- //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter
- return GetDatabaseFieldNameForOrderBy("umbracoNode", "nodeUser");
- case "PATH":
- return GetDatabaseFieldNameForOrderBy("umbracoNode", "path");
- case "SORTORDER":
- return GetDatabaseFieldNameForOrderBy("umbracoNode", "sortOrder");
- default:
- //ensure invalid SQL cannot be submitted
- return Regex.Replace(orderBy, @"[^\w\.,`\[\]@-]", "");
- }
+ var pos = s.InvariantIndexOf(atToken);
+ if (pos < 0) throw new Exception($"Could not find token \"{atToken}\".");
+ return s.Insert(pos, insert);
}
- protected string GetDatabaseFieldNameForOrderBy(string tableName, string fieldName)
+ protected Sql InsertJoins(Sql sql, Sql joins)
+ {
+ var joinsSql = joins.SQL;
+ var args = sql.Arguments;
+
+ // merge args if any
+ if (joins.Arguments.Length > 0)
+ {
+ var argsList = args.ToList();
+ joinsSql = ParameterHelper.ProcessParams(joinsSql, joins.Arguments, argsList);
+ args = argsList.ToArray();
+ }
+
+ return Sql(InsertBefore(sql.SQL, "WHERE", joinsSql), args);
+ }
+
+ protected string GetQuotedFieldName(string tableName, string fieldName)
{
return SqlContext.SqlSyntax.GetQuotedTableName(tableName) + "." + SqlContext.SqlSyntax.GetQuotedColumnName(fieldName);
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
index 28c0b0dec6..60aa155dc0 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
@@ -14,6 +14,7 @@ using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Scoping;
+using Umbraco.Core.Services;
using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
namespace Umbraco.Core.Persistence.Repositories.Implement
@@ -673,13 +674,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
PermissionRepository.Save(permission);
}
- ///
- /// Gets paged content results.
- ///
+ ///
public override IEnumerable GetPage(IQuery query,
- long pageIndex, int pageSize, out long totalRecords,
- string orderBy, Direction orderDirection, bool orderBySystemField,
- IQuery filter = null)
+ long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter, Ordering ordering)
{
Sql filterSql = null;
@@ -692,8 +690,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return GetPage(query, pageIndex, pageSize, out totalRecords,
x => MapDtosToContent(x),
- orderBy, orderDirection, orderBySystemField,
- filterSql);
+ filterSql,
+ ordering);
}
public bool IsPathPublished(IContent content)
@@ -814,25 +812,51 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
#endregion
- protected override string GetDatabaseFieldNameForOrderBy(string orderBy)
+ protected override string ApplySystemOrdering(ref Sql sql, Ordering ordering)
{
- // NOTE see sortby.prevalues.controller.js for possible values
- // that need to be handled here or in VersionableRepositoryBase
-
- //Some custom ones
- switch (orderBy.ToUpperInvariant())
+ // note: 'updater' is the user who created the latest draft version,
+ // we don't have an 'updater' per culture (should we?)
+ if (ordering.OrderBy.InvariantEquals("updater"))
{
- case "UPDATER":
- // fixme orders by id not letter = bad
- return GetDatabaseFieldNameForOrderBy(Constants.DatabaseSchema.Tables.ContentVersion, "userId");
- case "PUBLISHED":
- // fixme kill
- return GetDatabaseFieldNameForOrderBy(Constants.DatabaseSchema.Tables.Document, "published");
- case "CONTENTTYPEALIAS":
- throw new NotSupportedException("Don't know how to support ContentTypeAlias.");
+ var joins = Sql()
+ .InnerJoin("updaterUser").On((version, user) => version.UserId == user.Id, aliasRight: "updaterUser");
+
+ sql = InsertJoins(sql, joins);
+
+ return SqlSyntax.GetFieldName(x => x.UserName, "updaterUser");
}
- return base.GetDatabaseFieldNameForOrderBy(orderBy);
+ if (ordering.OrderBy.InvariantEquals("published"))
+ {
+ // no culture = can only work on the global 'published' flag
+ if (ordering.Culture.IsNullOrWhiteSpace())
+ return "(CASE WHEN pcv.id IS NULL THEN 0 ELSE 1 END)";
+
+ // invariant: left join will yield NULL and we must use pcv to determine published
+ // variant: left join may yield NULL or something, and that determines published
+
+ var joins = Sql()
+ .InnerJoin("ctype").On((content, contentType) => content.ContentTypeId == contentType.NodeId, aliasRight: "ctype")
+ .LeftJoin(nested =>
+ nested.InnerJoin("lang").On((ccv, lang) => ccv.LanguageId == lang.Id && lang.IsoCode == ordering.Culture, "ccv", "lang"), "ccv")
+ .On((pcv, ccv) => pcv.Id == ccv.VersionId, "pcv", "ccv"); // join on *published* content version
+
+ sql = InsertJoins(sql, joins);
+
+ // insert the SQL selected field, too, before the first FROM else ordering cannot work
+ // also: must insert the whole CASE body here, and only return 'opub', else NPoco paging code fails
+ var sqlText = InsertBefore(sql.SQL, "FROM",
+
+ // when invariant, ie 'variations' does not have the culture flag (value 1), use the global 'published' flag on pcv.id,
+ // otherwise check if there's a version culture variation for the lang, via ccv.id
+ ", (CASE WHEN (ctype.variations & 1) = 0 THEN (CASE WHEN pcv.id IS NULL THEN 0 ELSE 1 END) ELSE (CASE WHEN ccv.id IS NULL THEN 0 ELSE 1 END) END) AS opub "); // trailing space is important!
+
+ sql = Sql(sqlText, sql.Arguments);
+
+ return "opub";
+ }
+
+ return base.ApplySystemOrdering(ref sql, ordering);
}
private IEnumerable MapDtosToContent(List dtos, bool withCache = false)
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs
index 982a5bb885..f289547b10 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs
@@ -13,6 +13,7 @@ using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Scoping;
+using Umbraco.Core.Services;
namespace Umbraco.Core.Persistence.Repositories.Implement
{
@@ -455,11 +456,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
#endregion
- ///
- /// Gets paged media results.
- ///
- public override IEnumerable GetPage(IQuery query, long pageIndex, int pageSize, out long totalRecords,
- string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter = null)
+ ///
+ public override IEnumerable GetPage(IQuery query,
+ long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter, Ordering ordering)
{
Sql filterSql = null;
@@ -471,8 +471,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
return GetPage(query, pageIndex, pageSize, out totalRecords,
- x => MapDtosToContent(x), orderBy, orderDirection, orderBySystemField,
- filterSql);
+ x => MapDtosToContent(x),
+ filterSql,
+ ordering);
}
private IEnumerable MapDtosToContent(List dtos, bool withCache = false)
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs
index 98c38603b1..ee6727a32e 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs
@@ -11,6 +11,7 @@ using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Scoping;
+using Umbraco.Core.Services;
namespace Umbraco.Core.Persistence.Repositories.Implement
{
@@ -492,8 +493,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
///
/// Gets paged member results.
///
- public override IEnumerable GetPage(IQuery query, long pageIndex, int pageSize, out long totalRecords,
- string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter = null)
+ public override IEnumerable GetPage(IQuery query,
+ long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter,
+ Ordering ordering)
{
Sql filterSql = null;
@@ -505,8 +508,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
return GetPage(query, pageIndex, pageSize, out totalRecords,
- x => MapDtosToContent(x), orderBy, orderDirection, orderBySystemField,
- filterSql);
+ x => MapDtosToContent(x),
+ filterSql,
+ ordering);
}
private string _pagedResultsByQueryWhere;
@@ -523,20 +527,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return _pagedResultsByQueryWhere;
}
- protected override string GetDatabaseFieldNameForOrderBy(string orderBy)
+ protected override string ApplySystemOrdering(ref Sql sql, Ordering ordering)
{
- //Some custom ones
- switch (orderBy.ToUpperInvariant())
- {
- case "EMAIL":
- return GetDatabaseFieldNameForOrderBy("cmsMember", "email");
- case "LOGINNAME":
- return GetDatabaseFieldNameForOrderBy("cmsMember", "loginName");
- case "USERNAME":
- return GetDatabaseFieldNameForOrderBy("cmsMember", "loginName");
- }
+ if (ordering.OrderBy.InvariantEquals("email"))
+ return SqlSyntax.GetFieldName(x => x.Email);
- return base.GetDatabaseFieldNameForOrderBy(orderBy);
+ if (ordering.OrderBy.InvariantEquals("loginName"))
+ return SqlSyntax.GetFieldName(x => x.LoginName);
+
+ if (ordering.OrderBy.InvariantEquals("userName"))
+ return SqlSyntax.GetFieldName(x => x.LoginName);
+
+ return base.ApplySystemOrdering(ref sql, ordering);
}
private IEnumerable MapDtosToContent(List dtos, bool withCache = false)
diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs
index 2e788382fe..022bee8b41 100644
--- a/src/Umbraco.Core/Services/IContentService.cs
+++ b/src/Umbraco.Core/Services/IContentService.cs
@@ -166,31 +166,28 @@ namespace Umbraco.Core.Services
IEnumerable GetContentInRecycleBin();
///
- /// Gets child documents of a given parent.
+ /// Gets child documents of a parent.
///
/// The parent identifier.
/// The page number.
/// The page size.
/// Total number of documents.
- /// A field to order by.
- /// The ordering direction.
/// Search text filter.
+ /// Ordering infos.
IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
- string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
+ string filter = null, Ordering ordering = null);
///
- /// Gets child documents of a given parent.
+ /// Gets child documents of a parent.
///
/// The parent identifier.
/// The page number.
/// The page size.
/// Total number of documents.
- /// A field to order by.
- /// The ordering direction.
- /// A flag indicating whether the ordering field is a system field.
/// Query filter.
+ /// Ordering infos.
IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
- string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter);
+ IQuery filter, Ordering ordering = null);
///
/// Gets descendant documents of a given parent.
diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs
index da59615126..18dcf6beac 100644
--- a/src/Umbraco.Core/Services/Implement/ContentService.cs
+++ b/src/Umbraco.Core/Services/Implement/ContentService.cs
@@ -553,97 +553,47 @@ namespace Umbraco.Core.Services.Implement
}
}
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// Page index (zero based)
- /// 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, long pageIndex, int pageSize, out long totalChildren,
- string orderBy, Direction orderDirection, string filter = "")
+ string filter = null, Ordering ordering = null)
{
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.ContentTree);
- var filterQuery = filter.IsNullOrWhiteSpace()
- ? null
- : Query().Where(x => x.Name.Contains(filter));
+ var filterQuery = filter.IsNullOrWhiteSpace()
+ ? null
+ : Query().Where(x => x.Name.Contains(filter));
- return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery);
- }
+ return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, filterQuery, ordering);
}
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Children from
- /// Page index (zero based)
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Flag to indicate when ordering by system field
- ///
- /// An Enumerable list of objects
+ ///
public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
- string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter)
+ IQuery filter, Ordering ordering = null)
{
if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
+ if (ordering == null)
+ ordering = Ordering.By("sortOrder");
+
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.ContentTree);
- var query = Query();
- //if the id is System Root, then just get all - NO! does not make sense!
- //if (id != Constants.System.Root)
- query.Where(x => x.ParentId == id);
- return _documentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
+ var query = Query().Where(x => x.ParentId == id);
+ return _documentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering);
}
}
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Descendants 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 GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
{
- using (var scope = ScopeProvider.CreateScope(autoComplete: true))
- {
- scope.ReadLock(Constants.Locks.ContentTree);
- var filterQuery = filter.IsNullOrWhiteSpace()
- ? null
- : Query().Where(x => x.Name.Contains(filter));
+ var filterQuery = filter.IsNullOrWhiteSpace()
+ ? null
+ : Query().Where(x => x.Name.Contains(filter));
- return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery);
- }
+ return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filterQuery);
}
- ///
- /// Gets a collection of objects by Parent Id
- ///
- /// Id of the Parent to retrieve Descendants from
- /// Page number
- /// Page size
- /// Total records query would return without paging
- /// Field to order by
- /// Direction to order by
- /// Flag to indicate when ordering by system field
- /// Search filter
- /// An Enumerable list of objects
+ ///
public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter)
{
if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
@@ -654,6 +604,7 @@ namespace Umbraco.Core.Services.Implement
scope.ReadLock(Constants.Locks.ContentTree);
var query = Query();
+
//if the id is System Root, then just get all
if (id != Constants.System.Root)
{
@@ -665,7 +616,8 @@ namespace Umbraco.Core.Services.Implement
}
query.Where(x => x.Path.SqlStartsWith($"{contentPath[0].Path},", TextColumnType.NVarchar));
}
- return _documentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
+
+ return _documentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
}
}
diff --git a/src/Umbraco.Core/Services/Implement/MediaService.cs b/src/Umbraco.Core/Services/Implement/MediaService.cs
index 8f6a1c6000..431e20044c 100644
--- a/src/Umbraco.Core/Services/Implement/MediaService.cs
+++ b/src/Umbraco.Core/Services/Implement/MediaService.cs
@@ -515,14 +515,9 @@ namespace Umbraco.Core.Services.Implement
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.MediaTree);
- var query = Query();
- //if the id is System Root, then just get all - NO! does not make sense!
- //if (id != Constants.System.Root)
-
- query.Where(x => x.ParentId == id);
-
- return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
+ var query = Query().Where(x => x.ParentId == id);
+ return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
}
}
@@ -561,7 +556,7 @@ namespace Umbraco.Core.Services.Implement
var filterQuery = filter.IsNullOrWhiteSpace()
? null
: Query().Where(x => x.Name.Contains(filter));
- return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filterQuery);
+ return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filterQuery, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
}
}
@@ -607,6 +602,7 @@ namespace Umbraco.Core.Services.Implement
scope.ReadLock(Constants.Locks.MediaTree);
var query = Query();
+
//if the id is System Root, then just get all
if (id != Constants.System.Root)
{
@@ -618,7 +614,8 @@ namespace Umbraco.Core.Services.Implement
}
query.Where(x => x.Path.SqlStartsWith(mediaPath[0].Path + ",", TextColumnType.NVarchar));
}
- return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
+
+ return _mediaRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
}
}
diff --git a/src/Umbraco.Core/Services/Implement/MemberService.cs b/src/Umbraco.Core/Services/Implement/MemberService.cs
index 288809bf33..211e30d01c 100644
--- a/src/Umbraco.Core/Services/Implement/MemberService.cs
+++ b/src/Umbraco.Core/Services/Implement/MemberService.cs
@@ -387,7 +387,7 @@ namespace Umbraco.Core.Services.Implement
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.MemberTree);
- return _memberRepository.GetPage(null, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending, true);
+ return _memberRepository.GetPage(null, pageIndex, pageSize, out totalRecords, null, Ordering.By("LoginName"));
}
}
@@ -405,7 +405,7 @@ namespace Umbraco.Core.Services.Implement
scope.ReadLock(Constants.Locks.MemberTree);
var query1 = memberTypeAlias == null ? null : Query().Where(x => x.ContentTypeAlias == memberTypeAlias);
var query2 = filter == null ? null : Query().Where(x => x.Name.Contains(filter) || x.Username.Contains(filter) || x.Email.Contains(filter));
- return _memberRepository.GetPage(query1, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField, query2);
+ return _memberRepository.GetPage(query1, pageIndex, pageSize, out totalRecords, query2, Ordering.By(orderBy, orderDirection, isCustomField: !orderBySystemField));
}
}
@@ -557,7 +557,7 @@ namespace Umbraco.Core.Services.Implement
throw new ArgumentOutOfRangeException(nameof(matchType)); // causes rollback // causes rollback
}
- return _memberRepository.GetPage(query, pageIndex, pageSize, out totalRecords, "Name", Direction.Ascending, true);
+ return _memberRepository.GetPage(query, pageIndex, pageSize, out totalRecords, null, Ordering.By("Name"));
}
}
@@ -598,7 +598,7 @@ namespace Umbraco.Core.Services.Implement
throw new ArgumentOutOfRangeException(nameof(matchType));
}
- return _memberRepository.GetPage(query, pageIndex, pageSize, out totalRecords, "Email", Direction.Ascending, true);
+ return _memberRepository.GetPage(query, pageIndex, pageSize, out totalRecords, null, Ordering.By("Email"));
}
}
@@ -639,7 +639,7 @@ namespace Umbraco.Core.Services.Implement
throw new ArgumentOutOfRangeException(nameof(matchType));
}
- return _memberRepository.GetPage(query, pageIndex, pageSize, out totalRecords, "LoginName", Direction.Ascending, true);
+ return _memberRepository.GetPage(query, pageIndex, pageSize, out totalRecords, null, Ordering.By("LoginName"));
}
}
diff --git a/src/Umbraco.Core/Services/Ordering.cs b/src/Umbraco.Core/Services/Ordering.cs
new file mode 100644
index 0000000000..9713aa6bf5
--- /dev/null
+++ b/src/Umbraco.Core/Services/Ordering.cs
@@ -0,0 +1,81 @@
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
+
+namespace Umbraco.Core.Services
+{
+ ///
+ /// Represents ordering information.
+ ///
+ public class Ordering
+ {
+ private static readonly Ordering DefaultOrdering = new Ordering(null);
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the ordering field.
+ /// The ordering direction.
+ /// The (ISO) culture to consider when sorting multi-lingual fields.
+ /// A value indicating whether the ordering field is a custom user property.
+ ///
+ /// The can be null, meaning: not sorting. If it is the empty string, it becomes null.
+ /// The can be the empty string, meaning: invariant. If it is null, it becomes the empty string.
+ ///
+ public Ordering(string orderBy, Direction direction = Direction.Ascending, string culture = null, bool isCustomField = false)
+ {
+ OrderBy = orderBy.IfNullOrWhiteSpace(null); // empty is null and means, not sorting
+ Direction = direction;
+ Culture = culture.IfNullOrWhiteSpace(string.Empty); // empty is "" and means, invariant
+ IsCustomField = isCustomField;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ /// The name of the ordering field.
+ /// The ordering direction.
+ /// The (ISO) culture to consider when sorting multi-lingual fields.
+ /// A value indicating whether the ordering field is a custom user property.
+ ///
+ /// The can be null, meaning: not sorting. If it is the empty string, it becomes null.
+ /// The can be the empty string, meaning: invariant. If it is null, it becomes the empty string.
+ ///
+ public static Ordering By(string orderBy, Direction direction = Direction.Ascending, string culture = null, bool isCustomField = false)
+ => new Ordering(orderBy, direction, culture, isCustomField);
+
+ ///
+ /// Gets the default instance.
+ ///
+ public static Ordering ByDefault()
+ => DefaultOrdering;
+
+ ///
+ /// Gets the name of the ordering field.
+ ///
+ public string OrderBy { get; }
+
+ ///
+ /// Gets the ordering direction.
+ ///
+ public Direction Direction { get; }
+
+ ///
+ /// Gets (ISO) culture to consider when sorting multi-lingual fields.
+ ///
+ public string Culture { get; }
+
+ ///
+ /// Gets a value indicating whether the ordering field is a custom user property.
+ ///
+ public bool IsCustomField { get; }
+
+ ///
+ /// Gets a value indicating whether this ordering is the default ordering.
+ ///
+ public bool IsEmpty => this == DefaultOrdering || OrderBy == null;
+
+ ///
+ /// Gets a value indicating whether the culture of this ordering is invariant.
+ ///
+ public bool IsInvariant => this == DefaultOrdering || Culture == string.Empty;
+ }
+}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index e36f2eaf81..86004ef863 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -1391,6 +1391,7 @@
+
diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
index 29de77e6d8..7ff7c0a2e4 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
@@ -17,6 +17,7 @@ using Umbraco.Core.Persistence.Repositories.Implement;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Scoping;
+using Umbraco.Core.Services;
using Umbraco.Tests.Testing;
using Umbraco.Web.PropertyEditors;
@@ -760,7 +761,7 @@ namespace Umbraco.Tests.Persistence.Repositories
scope.Database.AsUmbracoDatabase().EnableSqlCount = true;
var query = scope.SqlContext.Query().Where(x => x.ParentId == root.Id);
- var result = repository.GetPage(query, 0, 20, out var totalRecords, "UpdateDate", Direction.Ascending, true);
+ var result = repository.GetPage(query, 0, 20, out var totalRecords, null, Ordering.By("UpdateDate"));
Assert.AreEqual(25, totalRecords);
foreach (var r in result)
@@ -803,12 +804,12 @@ namespace Umbraco.Tests.Persistence.Repositories
scope.Database.AsUmbracoDatabase().EnableSqlTrace = true;
scope.Database.AsUmbracoDatabase().EnableSqlCount = true;
- var result = repository.GetPage(query, 0, 2, out var totalRecords, "title", Direction.Ascending, false);
+ var result = repository.GetPage(query, 0, 2, out var totalRecords, null, Ordering.By("title", isCustomField: true));
Assert.AreEqual(3, totalRecords);
Assert.AreEqual(2, result.Count());
- result = repository.GetPage(query, 1, 2, out totalRecords, "title", Direction.Ascending, false);
+ result = repository.GetPage(query, 1, 2, out totalRecords, null, Ordering.By("title", isCustomField: true));
Assert.AreEqual(1, result.Count());
}
@@ -835,7 +836,7 @@ namespace Umbraco.Tests.Persistence.Repositories
scope.Database.AsUmbracoDatabase().EnableSqlTrace = true;
scope.Database.AsUmbracoDatabase().EnableSqlCount = true;
- var result = repository.GetPage(query, 0, 1, out var totalRecords, "Name", Direction.Ascending, true);
+ var result = repository.GetPage(query, 0, 1, out var totalRecords, null, Ordering.By("Name"));
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
Assert.That(result.Count(), Is.EqualTo(1));
@@ -858,7 +859,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var repository = CreateRepository((IScopeAccessor)provider, out _);
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
- var result = repository.GetPage(query, 1, 1, out var totalRecords, "Name", Direction.Ascending, true);
+ var result = repository.GetPage(query, 1, 1, out var totalRecords, null, Ordering.By("Name"));
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
Assert.That(result.Count(), Is.EqualTo(1));
@@ -875,7 +876,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var repository = CreateRepository((IScopeAccessor)provider, out _);
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
- var result = repository.GetPage(query, 0, 2, out var totalRecords, "Name", Direction.Ascending, true);
+ var result = repository.GetPage(query, 0, 2, out var totalRecords, null, Ordering.By("Name"));
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
Assert.That(result.Count(), Is.EqualTo(2));
@@ -892,7 +893,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var repository = CreateRepository((IScopeAccessor)provider, out _);
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
- var result = repository.GetPage(query, 0, 1, out var totalRecords, "Name", Direction.Descending, true);
+ var result = repository.GetPage(query, 0, 1, out var totalRecords, null, Ordering.By("Name", Direction.Descending));
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
Assert.That(result.Count(), Is.EqualTo(1));
@@ -911,7 +912,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
var filterQuery = scope.SqlContext.Query().Where(x => x.Name.Contains("Page 2"));
- var result = repository.GetPage(query, 0, 1, out var totalRecords, "Name", Direction.Ascending, true, filterQuery);
+ var result = repository.GetPage(query, 0, 1, out var totalRecords, filterQuery, Ordering.By("Name"));
Assert.That(totalRecords, Is.EqualTo(1));
Assert.That(result.Count(), Is.EqualTo(1));
@@ -930,7 +931,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
var filterQuery = scope.SqlContext.Query().Where(x => x.Name.Contains("text"));
- var result = repository.GetPage(query, 0, 1, out var totalRecords, "Name", Direction.Ascending, true, filterQuery);
+ var result = repository.GetPage(query, 0, 1, out var totalRecords, filterQuery, Ordering.By("Name"));
Assert.That(totalRecords, Is.EqualTo(2));
Assert.That(result.Count(), Is.EqualTo(1));
diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs
index 87759db3df..d1e7f96ff3 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs
@@ -326,7 +326,7 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
long totalRecords;
- var result = repository.GetPage(query, 0, 1, out totalRecords, "SortOrder", Direction.Ascending, true);
+ var result = repository.GetPage(query, 0, 1, out totalRecords, null, Ordering.By("SortOrder"));
// Assert
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
@@ -348,7 +348,7 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
long totalRecords;
- var result = repository.GetPage(query, 1, 1, out totalRecords, "SortOrder", Direction.Ascending, true);
+ var result = repository.GetPage(query, 1, 1, out totalRecords, null, Ordering.By("SortOrder"));
// Assert
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
@@ -370,7 +370,7 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
long totalRecords;
- var result = repository.GetPage(query, 0, 2, out totalRecords, "SortOrder", Direction.Ascending, true);
+ var result = repository.GetPage(query, 0, 2, out totalRecords, null, Ordering.By("SortOrder"));
// Assert
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
@@ -392,7 +392,7 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
long totalRecords;
- var result = repository.GetPage(query, 0, 1, out totalRecords, "SortOrder", Direction.Descending, true);
+ var result = repository.GetPage(query, 0, 1, out totalRecords, null, Ordering.By("SortOrder", Direction.Descending));
// Assert
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
@@ -413,8 +413,7 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
- long totalRecords;
- var result = repository.GetPage(query, 0, 1, out totalRecords, "Name", Direction.Ascending, true);
+ var result = repository.GetPage(query, 0, 1, out var totalRecords, null, Ordering.By("Name"));
// Assert
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
@@ -435,10 +434,9 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
- long totalRecords;
var filter = scope.SqlContext.Query().Where(x => x.Name.Contains("File"));
- var result = repository.GetPage(query, 0, 1, out totalRecords, "SortOrder", Direction.Ascending, true, filter);
+ var result = repository.GetPage(query, 0, 1, out var totalRecords, filter, Ordering.By("SortOrder"));
// Assert
Assert.That(totalRecords, Is.EqualTo(1));
@@ -454,15 +452,13 @@ namespace Umbraco.Tests.Persistence.Repositories
var provider = TestObjects.GetScopeProvider(Logger);
using (var scope = provider.CreateScope())
{
- MediaTypeRepository mediaTypeRepository;
- var repository = CreateRepository(provider, out mediaTypeRepository);
+ var repository = CreateRepository(provider, out _);
// Act
var query = scope.SqlContext.Query().Where(x => x.Level == 2);
- long totalRecords;
var filter = scope.SqlContext.Query().Where(x => x.Name.Contains("Test"));
- var result = repository.GetPage(query, 0, 1, out totalRecords, "SortOrder", Direction.Ascending, true, filter);
+ var result = repository.GetPage(query, 0, 1, out var totalRecords, filter, Ordering.By("SortOrder"));
// Assert
Assert.That(totalRecords, Is.EqualTo(2));
diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs
index a0ba648ddd..1bc8ff326d 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -457,10 +457,10 @@ namespace Umbraco.Web.Editors
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "",
- string cultureName = "")
+ string cultureName = "") // TODO it's not a NAME it's the ISO CODE
{
long totalChildren;
- IContent[] children;
+ List children;
if (pageNumber > 0 && pageSize > 0)
{
IQuery queryFilter = null;
@@ -472,16 +472,14 @@ namespace Umbraco.Web.Editors
}
children = Services.ContentService
- .GetPagedChildren(
- id, (pageNumber - 1), pageSize,
- out totalChildren,
- orderBy, orderDirection, orderBySystemField,
- queryFilter).ToArray();
+ .GetPagedChildren(id, pageNumber - 1, pageSize, out totalChildren,
+ queryFilter,
+ Ordering.By(orderBy, orderDirection, cultureName, !orderBySystemField)).ToList();
}
else
{
- children = Services.ContentService.GetChildren(id).ToArray();
- totalChildren = children.Length;
+ children = Services.ContentService.GetChildren(id).ToList();
+ totalChildren = children.Count;
}
if (totalChildren == 0)
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
index a39f034a39..d5d90b8479 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
@@ -1277,7 +1277,7 @@ WHERE cmsContentNu.nodeId IN (
long total;
do
{
- var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, "Path", Direction.Ascending, true);
+ var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path"));
var items = new List();
foreach (var c in descendants)
{
@@ -1344,7 +1344,7 @@ WHERE cmsContentNu.nodeId IN (
long total;
do
{
- var descendants = _mediaRepository.GetPage(query, pageIndex++, groupSize, out total, "Path", Direction.Ascending, true);
+ var descendants = _mediaRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path"));
var items = descendants.Select(m => GetDto(m, false)).ToArray();
db.BulkInsertRecords(items);
processed += items.Length;
@@ -1402,7 +1402,7 @@ WHERE cmsContentNu.nodeId IN (
long total;
do
{
- var descendants = _memberRepository.GetPage(query, pageIndex++, groupSize, out total, "Path", Direction.Ascending, true);
+ var descendants = _memberRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path"));
var items = descendants.Select(m => GetDto(m, false)).ToArray();
db.BulkInsertRecords(items);
processed += items.Length;
diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs
index 5b640f13e5..5fa89e3f7b 100644
--- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs
+++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs
@@ -1746,7 +1746,7 @@ WHERE cmsContentXml.nodeId IN (
long total;
do
{
- var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, "Path", Direction.Ascending, true);
+ var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path"));
const bool published = true; // contentXml contains published content!
var items = descendants.Select(c => new ContentXmlDto { NodeId = c.Id, Xml =
EntityXmlSerializer.Serialize(_serviceContext.ContentService, _serviceContext.DataTypeService, _serviceContext.UserService, _serviceContext.LocalizationService, _segmentProviders, c, published).ToDataString() }).ToArray();
@@ -1819,7 +1819,7 @@ WHERE cmsPreviewXml.nodeId IN (
{
// .GetPagedResultsByQuery implicitely adds ({Constants.DatabaseSchema.Tables.Document}.newest = 1) which
// is what we want for preview (ie latest version of a content, published or not)
- var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, "Path", Direction.Ascending, true);
+ var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path"));
const bool published = true; // previewXml contains edit content!
var items = descendants.Select(c => new PreviewXmlDto
{
@@ -1892,7 +1892,7 @@ WHERE cmsContentXml.nodeId IN (
long total;
do
{
- var descendants = _mediaRepository.GetPage(query, pageIndex++, groupSize, out total, "Path", Direction.Ascending, true);
+ var descendants = _mediaRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path"));
var items = descendants.Select(m => new ContentXmlDto { NodeId = m.Id, Xml =
EntityXmlSerializer.Serialize(_serviceContext.MediaService, _serviceContext.DataTypeService, _serviceContext.UserService, _serviceContext.LocalizationService, _segmentProviders, m).ToDataString() }).ToArray();
db.BulkInsertRecords(items);
@@ -1961,7 +1961,7 @@ WHERE cmsContentXml.nodeId IN (
long total;
do
{
- var descendants = _memberRepository.GetPage(query, pageIndex++, groupSize, out total, "Path", Direction.Ascending, true);
+ var descendants = _memberRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path"));
var items = descendants.Select(m => new ContentXmlDto { NodeId = m.Id, Xml = EntityXmlSerializer.Serialize(_serviceContext.DataTypeService, _serviceContext.LocalizationService, m).ToDataString() }).ToArray();
db.BulkInsertRecords(items);
processed += items.Length;