diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs
index fbb68194b7..2ea0fd855b 100644
--- a/src/Umbraco.Core/Models/ContentBase.cs
+++ b/src/Umbraco.Core/Models/ContentBase.cs
@@ -108,6 +108,9 @@ namespace Umbraco.Core.Models
[IgnoreDataMember]
public int VersionId { get; set; }
+ [DataMember]
+ public Guid NodeObjectType { get; internal set; }
+
///
/// Integer Id of the default ContentType
///
diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs
index 04bcb7424a..1f3f1a5c13 100644
--- a/src/Umbraco.Core/Models/ContentTypeBase.cs
+++ b/src/Umbraco.Core/Models/ContentTypeBase.cs
@@ -113,6 +113,9 @@ namespace Umbraco.Core.Models
OnPropertyChanged(nameof(PropertyTypes));
}
+ [DataMember]
+ public Guid NodeObjectType { get; internal set; }
+
///
/// The Alias of the ContentType
///
diff --git a/src/Umbraco.Core/Models/DataType.cs b/src/Umbraco.Core/Models/DataType.cs
index c237f6381c..cba53bbd10 100644
--- a/src/Umbraco.Core/Models/DataType.cs
+++ b/src/Umbraco.Core/Models/DataType.cs
@@ -65,6 +65,9 @@ namespace Umbraco.Core.Models
[DataMember]
public string EditorAlias => _editor.Alias;
+ [DataMember]
+ public Guid NodeObjectType { get; internal set; }
+
///
[DataMember]
public ValueStorageType DatabaseType
diff --git a/src/Umbraco.Core/Models/Entities/ITreeEntity.cs b/src/Umbraco.Core/Models/Entities/ITreeEntity.cs
index afa3399202..ab63e1e1d8 100644
--- a/src/Umbraco.Core/Models/Entities/ITreeEntity.cs
+++ b/src/Umbraco.Core/Models/Entities/ITreeEntity.cs
@@ -24,7 +24,7 @@
/// Sets the parent entity.
///
/// Use this method to set the parent entity when the parent entity is known, but has not
- /// been persistent and does not yet have an identity. The parent identifier will we retrieved
+ /// been persistent and does not yet have an identity. The parent identifier will be retrieved
/// from the parent entity when needed. If the parent entity still does not have an entity by that
/// time, an exception will be thrown by getter.
void SetParent(ITreeEntity parent);
@@ -53,4 +53,4 @@
///
bool Trashed { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Core/Models/Entities/IUmbracoEntity.cs b/src/Umbraco.Core/Models/Entities/IUmbracoEntity.cs
index e5f628b098..13087b5e95 100644
--- a/src/Umbraco.Core/Models/Entities/IUmbracoEntity.cs
+++ b/src/Umbraco.Core/Models/Entities/IUmbracoEntity.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
namespace Umbraco.Core.Models.Entities
{
@@ -11,5 +12,7 @@ namespace Umbraco.Core.Models.Entities
/// An IUmbracoEntity can participate in notifications.
///
public interface IUmbracoEntity : ITreeEntity, IRememberBeingDirty
- { }
+ {
+ Guid NodeObjectType { get; }
+ }
}
diff --git a/src/Umbraco.Core/Models/EntityContainer.cs b/src/Umbraco.Core/Models/EntityContainer.cs
index 70f6cbd878..71a477a9d6 100644
--- a/src/Umbraco.Core/Models/EntityContainer.cs
+++ b/src/Umbraco.Core/Models/EntityContainer.cs
@@ -62,6 +62,8 @@ namespace Umbraco.Core.Models
///
public Guid ContainerObjectType => ObjectTypeMap[_containedObjectType];
+ Guid IUmbracoEntity.NodeObjectType => ContainerObjectType;
+
///
/// Gets the container object type corresponding to a contained object type.
///
diff --git a/src/Umbraco.Core/Models/SimpleContentType.cs b/src/Umbraco.Core/Models/SimpleContentType.cs
index 5c81017ec8..b4e7688eea 100644
--- a/src/Umbraco.Core/Models/SimpleContentType.cs
+++ b/src/Umbraco.Core/Models/SimpleContentType.cs
@@ -44,11 +44,14 @@ namespace Umbraco.Core.Models
Name = contentType.Name;
AllowedAsRoot = contentType.AllowedAsRoot;
IsElement = contentType.IsElement;
+ NodeObjectType = contentType.NodeObjectType;
}
///
public string Alias { get; }
+ public Guid NodeObjectType { get; }
+
public int Id { get; }
///
diff --git a/src/Umbraco.Core/Persistence/Factories/ContentBaseFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentBaseFactory.cs
index 434e0393cd..25cc6bc358 100644
--- a/src/Umbraco.Core/Persistence/Factories/ContentBaseFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/ContentBaseFactory.cs
@@ -34,7 +34,7 @@ namespace Umbraco.Core.Persistence.Factories
content.VersionId = contentVersionDto.Id;
content.Name = contentVersionDto.Text;
-
+ content.NodeObjectType = nodeDto.NodeObjectType ?? Guid.Empty;
content.Path = nodeDto.Path;
content.Level = nodeDto.Level;
content.ParentId = nodeDto.ParentId;
diff --git a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs
index 54cfee0ffa..46489aa69e 100644
--- a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs
@@ -107,6 +107,7 @@ namespace Umbraco.Core.Persistence.Factories
{
entity.Id = dto.NodeDto.NodeId;
entity.Key = dto.NodeDto.UniqueId;
+ entity.NodeObjectType = dto.NodeDto.NodeObjectType ?? Guid.Empty;
entity.Alias = dto.Alias;
entity.Name = dto.NodeDto.Text;
entity.Icon = dto.Icon;
diff --git a/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
index f189d38d05..5d92234ca8 100644
--- a/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
@@ -28,6 +28,7 @@ namespace Umbraco.Core.Persistence.Factories
dataType.DisableChangeTracking();
dataType.CreateDate = dto.NodeDto.CreateDate;
+ dataType.NodeObjectType = dto.NodeDto.NodeObjectType ?? Guid.Empty;
dataType.DatabaseType = dto.DbType.EnumParse(true);
dataType.Id = dto.NodeId;
dataType.Key = dto.NodeDto.UniqueId;
diff --git a/src/Umbraco.Core/Persistence/Mappers/UmbracoEntityMapper.cs b/src/Umbraco.Core/Persistence/Mappers/UmbracoEntityMapper.cs
index 16e2e8bcd5..96f664cc25 100644
--- a/src/Umbraco.Core/Persistence/Mappers/UmbracoEntityMapper.cs
+++ b/src/Umbraco.Core/Persistence/Mappers/UmbracoEntityMapper.cs
@@ -24,6 +24,7 @@ namespace Umbraco.Core.Persistence.Mappers
DefineMap(nameof(IUmbracoEntity.Trashed), nameof(NodeDto.Trashed));
DefineMap(nameof(IUmbracoEntity.Key), nameof(NodeDto.UniqueId));
DefineMap(nameof(IUmbracoEntity.CreatorId), nameof(NodeDto.UserId));
+ DefineMap(nameof(IUmbracoEntity.NodeObjectType), nameof(NodeDto.NodeObjectType));
}
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/IEntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IEntityRepository.cs
index 69f6ef4c5f..a6a1691347 100644
--- a/src/Umbraco.Core/Persistence/Repositories/IEntityRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/IEntityRepository.cs
@@ -15,10 +15,22 @@ namespace Umbraco.Core.Persistence.Repositories
IEntitySlim Get(int id, Guid objectTypeId);
IEntitySlim Get(Guid key, Guid objectTypeId);
- IEnumerable GetAll(Guid objectType, params int[] ids);
+ IEnumerable GetAll(Guid objectType, params int[] ids);
IEnumerable GetAll(Guid objectType, params Guid[] keys);
+ ///
+ /// Gets entities for a query
+ ///
+ ///
+ ///
IEnumerable GetByQuery(IQuery query);
+
+ ///
+ /// Gets entities for a query and a specific object type allowing the query to be slightly more optimized
+ ///
+ ///
+ ///
+ ///
IEnumerable GetByQuery(IQuery query, Guid objectType);
UmbracoObjectTypes GetObjectType(int id);
@@ -30,7 +42,36 @@ namespace Umbraco.Core.Persistence.Repositories
bool Exists(int id);
bool Exists(Guid key);
+ ///
+ /// Gets paged entities for a query and a subset of object types
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// A collection of mixed entity types which would be of type , , ,
+ ///
+ ///
+ IEnumerable GetPagedResultsByQuery(IQuery query, Guid[] objectTypes, long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter, Ordering ordering);
+
+ ///
+ /// Gets paged entities for a query and a specific object type
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
IEnumerable GetPagedResultsByQuery(IQuery query, Guid objectType, long pageIndex, int pageSize, out long totalRecords,
IQuery filter, Ordering ordering);
+
+
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs
index 161db543ba..2b68c8fe19 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs
@@ -36,26 +36,70 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
#region Repository
- // get a page of entities
+ //public IEnumerable GetPagedResults(IDictionary> typesAndIds, long pageIndex, int pageSize, out long totalRecords, Ordering ordering)
+ //{
+ // var isContent = typesAndIds.Keys.Any(objectType => objectType == Constants.ObjectTypes.Document || objectType == Constants.ObjectTypes.DocumentBlueprint);
+ // var isMedia = typesAndIds.Keys.Any(objectType => objectType == Constants.ObjectTypes.Media);
+ // var isMember = typesAndIds.Keys.Any(objectType => objectType == Constants.ObjectTypes.Member);
+
+ // var sql = GetBase(isContent, isMedia, isMember, null, false)
+ // .WhereIn(x => x.NodeObjectType, typesAndIds.Keys);
+
+ // ordering = ordering ?? Ordering.ByDefault();
+
+ // sql = AddGroupBy(isContent, isMedia, isMember, sql, ordering.IsEmpty);
+
+ // if (!ordering.IsEmpty)
+ // {
+ // // apply ordering
+ // ApplyOrdering(ref sql, ordering);
+ // }
+
+ // // TODO: we should be able to do sql = sql.OrderBy(x => Alias(x.NodeId, "NodeId")); but we can't because the OrderBy extension don't support Alias currently
+ // //no matter what we always must have node id ordered at the end
+ // sql = ordering.Direction == Direction.Ascending ? sql.OrderBy("NodeId") : sql.OrderByDescending("NodeId");
+
+ // // for content we must query for ContentEntityDto entities to produce the correct culture variant entity names
+ // var pageIndexToFetch = pageIndex + 1;
+ // IEnumerable dtos;
+ // var page = Database.Page(pageIndexToFetch, pageSize, sql);
+ // dtos = page.Items;
+ // totalRecords = page.TotalItems;
+
+ // var entities = dtos.Select(BuildEntity).ToArray();
+
+ // BuildVariants(entities.OfType());
+
+ // return entities;
+ //}
+
public IEnumerable GetPagedResultsByQuery(IQuery query, Guid objectType, long pageIndex, int pageSize, out long totalRecords,
IQuery filter, Ordering ordering)
{
- var isContent = objectType == Constants.ObjectTypes.Document || objectType == Constants.ObjectTypes.DocumentBlueprint;
- var isMedia = objectType == Constants.ObjectTypes.Media;
- var isMember = objectType == Constants.ObjectTypes.Member;
+ query = query.Where(x => x.NodeObjectType == objectType);
+ return GetPagedResultsByQuery(query, new[] { objectType }, pageIndex, pageSize, out totalRecords, filter, ordering);
+ }
+
+ // get a page of entities
+ public IEnumerable GetPagedResultsByQuery(IQuery query, Guid[] objectTypes, long pageIndex, int pageSize, out long totalRecords,
+ IQuery filter, Ordering ordering)
+ {
+ var isContent = objectTypes.Any(objectType => objectType == Constants.ObjectTypes.Document || objectType == Constants.ObjectTypes.DocumentBlueprint);
+ var isMedia = objectTypes.Any(objectType => objectType == Constants.ObjectTypes.Media);
+ var isMember = objectTypes.Any(objectType => objectType == Constants.ObjectTypes.Member);
var sql = GetBaseWhere(isContent, isMedia, isMember, false, x =>
{
if (filter == null) return;
foreach (var filterClause in filter.GetWhereClauses())
x.Where(filterClause.Item1, filterClause.Item2);
- }, objectType);
+ }, objectTypes);
ordering = ordering ?? Ordering.ByDefault();
var translator = new SqlTranslator(sql, query);
sql = translator.Translate();
- sql = AddGroupBy(isContent, isMedia, isMember, sql, ordering.IsEmpty);
+ sql = AddGroupBy(true, true, true, sql, ordering.IsEmpty);
if (!ordering.IsEmpty)
{
@@ -70,35 +114,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// for content we must query for ContentEntityDto entities to produce the correct culture variant entity names
var pageIndexToFetch = pageIndex + 1;
IEnumerable dtos;
- if(isContent)
- {
- var page = Database.Page(pageIndexToFetch, pageSize, sql);
- dtos = page.Items;
- totalRecords = page.TotalItems;
- }
- else if (isMedia)
- {
- var page = Database.Page(pageIndexToFetch, pageSize, sql);
- dtos = page.Items;
- totalRecords = page.TotalItems;
- }
- else if (isMember)
- {
- var page = Database.Page(pageIndexToFetch, pageSize, sql);
- dtos = page.Items;
- totalRecords = page.TotalItems;
- }
- else
- {
- var page = Database.Page(pageIndexToFetch, pageSize, sql);
- dtos = page.Items;
- totalRecords = page.TotalItems;
- }
+ var page = Database.Page(pageIndexToFetch, pageSize, sql);
+ dtos = page.Items;
+ totalRecords = page.TotalItems;
- var entities = dtos.Select(x => BuildEntity(isContent, isMedia, isMember, x)).ToArray();
+ var entities = dtos.Select(BuildEntity).ToArray();
- if (isContent)
- BuildVariants(entities.Cast());
+ BuildVariants(entities.OfType());
return entities;
}
@@ -107,7 +129,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
var sql = GetBaseWhere(false, false, false, false, key);
var dto = Database.FirstOrDefault(sql);
- return dto == null ? null : BuildEntity(false, false, false, dto);
+ return dto == null ? null : BuildEntity(dto);
}
@@ -116,7 +138,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
//isContent is going to return a 1:M result now with the variants so we need to do different things
if (isContent)
{
- var cdtos = Database.Fetch(sql);
+ var cdtos = Database.Fetch(sql);
return cdtos.Count == 0 ? null : BuildVariants(BuildDocumentEntity(cdtos[0]));
}
@@ -127,7 +149,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (dto == null) return null;
- var entity = BuildEntity(false, isMedia, isMember, dto);
+ var entity = BuildEntity(dto);
return entity;
}
@@ -146,7 +168,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
var sql = GetBaseWhere(false, false, false, false, id);
var dto = Database.FirstOrDefault(sql);
- return dto == null ? null : BuildEntity(false, false, false, dto);
+ return dto == null ? null : BuildEntity(dto);
}
public IEntitySlim Get(int id, Guid objectTypeId)
@@ -178,7 +200,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
//isContent is going to return a 1:M result now with the variants so we need to do different things
if (isContent)
{
- var cdtos = Database.Fetch(sql);
+ var cdtos = Database.Fetch(sql);
return cdtos.Count == 0
? Enumerable.Empty()
@@ -189,7 +211,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
? (IEnumerable)Database.Fetch(sql)
: Database.Fetch(sql);
- var entities = dtos.Select(x => BuildEntity(false, isMedia, isMember, x)).ToArray();
+ var entities = dtos.Select(BuildEntity).ToArray();
return entities;
}
@@ -233,7 +255,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var sql = translator.Translate();
sql = AddGroupBy(false, false, false, sql, true);
var dtos = Database.Fetch(sql);
- return dtos.Select(x => BuildEntity(false, false, false, x)).ToList();
+ return dtos.Select(BuildEntity).ToList();
}
public IEnumerable GetByQuery(IQuery query, Guid objectType)
@@ -242,7 +264,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var isMedia = objectType == Constants.ObjectTypes.Media;
var isMember = objectType == Constants.ObjectTypes.Member;
- var sql = GetBaseWhere(isContent, isMedia, isMember, false, null, objectType);
+ var sql = GetBaseWhere(isContent, isMedia, isMember, false, null, new[] { objectType });
var translator = new SqlTranslator(sql, query);
sql = translator.Translate();
@@ -356,14 +378,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// gets the full sql for a given object type, with a given filter
protected Sql GetFullSqlForEntityType(bool isContent, bool isMedia, bool isMember, Guid objectType, Action> filter)
{
- var sql = GetBaseWhere(isContent, isMedia, isMember, false, filter, objectType);
+ var sql = GetBaseWhere(isContent, isMedia, isMember, false, filter, new[] { objectType });
return AddGroupBy(isContent, isMedia, isMember, sql, true);
}
// gets the base SELECT + FROM [+ filter] sql
// always from the 'current' content version
protected Sql GetBase(bool isContent, bool isMedia, bool isMember, Action> filter, bool isCount = false)
- {
+ {
var sql = Sql();
if (isCount)
@@ -401,15 +423,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (isContent || isMedia || isMember)
{
sql
- .InnerJoin().On((left, right) => left.NodeId == right.NodeId && right.Current)
- .InnerJoin().On((left, right) => left.NodeId == right.NodeId)
- .InnerJoin().On((left, right) => left.ContentTypeId == right.NodeId);
+ .LeftJoin().On((left, right) => left.NodeId == right.NodeId && right.Current)
+ .LeftJoin().On((left, right) => left.NodeId == right.NodeId)
+ .LeftJoin().On((left, right) => left.ContentTypeId == right.NodeId);
}
if (isContent)
{
sql
- .InnerJoin().On((left, right) => left.NodeId == right.NodeId);
+ .LeftJoin().On((left, right) => left.NodeId == right.NodeId);
}
if (isMedia)
@@ -433,10 +455,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// gets the base SELECT + FROM [+ filter] + WHERE sql
// for a given object type, with a given filter
- protected Sql GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Action> filter, Guid objectType)
+ protected Sql GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Action> filter, Guid[] objectTypes)
{
return GetBase(isContent, isMedia, isMember, filter, isCount)
- .Where(x => x.NodeObjectType == objectType);
+ .WhereIn(x => x.NodeObjectType, objectTypes);
}
// gets the base SELECT + FROM + WHERE sql
@@ -510,8 +532,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (sql == null) throw new ArgumentNullException(nameof(sql));
if (ordering == null) throw new ArgumentNullException(nameof(ordering));
- // TODO: although this works for name, it probably doesn't work for others without an alias of some sort
- var orderBy = ordering.OrderBy;
+ // TODO: although the default ordering string works for name, it wont work for others without a table or an alias of some sort
+ // As more things are attempted to be sorted we'll prob have to add more expressions here
+ var orderBy = ordering.OrderBy.ToUpperInvariant() switch
+ {
+ "PATH" => SqlSyntax.GetQuotedColumn(NodeDto.TableName, "path"),
+ _ => ordering.OrderBy
+ };
if (ordering.Direction == Direction.Ascending)
sql.OrderBy(orderBy);
@@ -524,9 +551,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
#region Classes
///
- /// The DTO used to fetch results for a content item with its variation info
+ /// The DTO used to fetch results for a generic content item which could be either a document, media or a member
///
- private class ContentEntityDto : BaseDto
+ private class GenericContentEntityDto : DocumentEntityDto
+ {
+ public string MediaPath { get; set; }
+ }
+
+ ///
+ /// The DTO used to fetch results for a document item with its variation info
+ ///
+ private class DocumentEntityDto : BaseDto
{
public ContentVariation Variations { get; set; }
@@ -534,11 +569,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public bool Edited { get; set; }
}
+ ///
+ /// The DTO used to fetch results for a media item with its media path info
+ ///
private class MediaEntityDto : BaseDto
{
public string MediaPath { get; set; }
}
+ ///
+ /// The DTO used to fetch results for a member item
+ ///
private class MemberEntityDto : BaseDto
{
}
@@ -589,13 +630,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
#region Factory
- private EntitySlim BuildEntity(bool isContent, bool isMedia, bool isMember, BaseDto dto)
+ private EntitySlim BuildEntity(BaseDto dto)
{
- if (isContent)
+ if (dto.NodeObjectType == Constants.ObjectTypes.Document)
return BuildDocumentEntity(dto);
- if (isMedia)
+ if (dto.NodeObjectType == Constants.ObjectTypes.Media)
return BuildMediaEntity(dto);
- if (isMember)
+ if (dto.NodeObjectType == Constants.ObjectTypes.Member)
return BuildMemberEntity(dto);
// EntitySlim does not track changes
@@ -650,7 +691,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var entity = new DocumentEntitySlim();
BuildContentEntity(entity, dto);
- if (dto is ContentEntityDto contentDto)
+ if (dto is DocumentEntityDto contentDto)
{
// fill in the invariant info
entity.Edited = contentDto.Edited;
diff --git a/src/Umbraco.Tests/Persistence/Repositories/EntityRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/EntityRepositoryTest.cs
new file mode 100644
index 0000000000..a4df5bcf78
--- /dev/null
+++ b/src/Umbraco.Tests/Persistence/Repositories/EntityRepositoryTest.cs
@@ -0,0 +1,95 @@
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using Umbraco.Core;
+using Umbraco.Core.Models;
+using Umbraco.Core.Models.Entities;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.Repositories.Implement;
+using Umbraco.Core.Scoping;
+using Umbraco.Tests.TestHelpers;
+using Umbraco.Tests.TestHelpers.Entities;
+using Umbraco.Tests.Testing;
+
+namespace Umbraco.Tests.Persistence.Repositories
+{
+ [TestFixture]
+ [UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
+ public class EntityRepositoryTest : TestWithDatabaseBase
+ {
+
+ private EntityRepository CreateRepository(IScopeAccessor scopeAccessor)
+ {
+ var entityRepository = new EntityRepository(scopeAccessor);
+ return entityRepository;
+ }
+
+ [Test]
+ public void Get_Paged_Mixed_Entities_By_Ids()
+ {
+ //Create content
+
+ var createdContent = new List();
+ var contentType = MockedContentTypes.CreateBasicContentType("blah");
+ ServiceContext.ContentTypeService.Save(contentType);
+ for (int i = 0; i < 10; i++)
+ {
+ var c1 = MockedContent.CreateBasicContent(contentType);
+ ServiceContext.ContentService.Save(c1);
+ createdContent.Add(c1);
+ }
+
+ //Create media
+
+ var createdMedia = new List();
+ var imageType = MockedContentTypes.CreateImageMediaType("myImage");
+ ServiceContext.MediaTypeService.Save(imageType);
+ for (int i = 0; i < 10; i++)
+ {
+ var c1 = MockedMedia.CreateMediaImage(imageType, -1);
+ ServiceContext.MediaService.Save(c1);
+ createdMedia.Add(c1);
+ }
+
+ // Create members
+ var memberType = MockedContentTypes.CreateSimpleMemberType("simple");
+ ServiceContext.MemberTypeService.Save(memberType);
+ var createdMembers = MockedMember.CreateSimpleMember(memberType, 10).ToList();
+ ServiceContext.MemberService.Save(createdMembers);
+
+ var provider = TestObjects.GetScopeProvider(Logger);
+ using (var scope = provider.CreateScope())
+ {
+ var repo = CreateRepository((IScopeAccessor)provider);
+
+ var ids = createdContent.Select(x => x.Id).Concat(createdMedia.Select(x => x.Id)).Concat(createdMembers.Select(x => x.Id));
+
+ var objectTypes = new[] { Constants.ObjectTypes.Document, Constants.ObjectTypes.Media, Constants.ObjectTypes.Member };
+
+ var query = SqlContext.Query()
+ .WhereIn(e => e.Id, ids);
+
+ var entities = repo.GetPagedResultsByQuery(query, objectTypes, 0, 20, out var totalRecords, null, null).ToList();
+
+ Assert.AreEqual(20, entities.Count);
+ Assert.AreEqual(30, totalRecords);
+
+ //add the next page
+ entities.AddRange(repo.GetPagedResultsByQuery(query, objectTypes, 1, 20, out totalRecords, null, null));
+
+ Assert.AreEqual(30, entities.Count);
+ Assert.AreEqual(30, totalRecords);
+
+ var contentEntities = entities.OfType().ToList();
+ var mediaEntities = entities.OfType().ToList();
+ var memberEntities = entities.OfType().ToList();
+
+ Assert.AreEqual(10, contentEntities.Count);
+ Assert.AreEqual(10, mediaEntities.Count);
+ Assert.AreEqual(10, memberEntities.Count);
+ }
+
+ }
+
+ }
+}
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 4b035f631e..c87e6501f9 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -140,6 +140,7 @@
+
diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs
index 0513017b70..11b1260e71 100644
--- a/src/Umbraco.Web/Editors/EntityController.cs
+++ b/src/Umbraco.Web/Editors/EntityController.cs
@@ -662,6 +662,9 @@ namespace Umbraco.Web.Editors
if (pageSize <= 0)
throw new HttpResponseException(HttpStatusCode.NotFound);
+ // re-normalize since NULL can be passed in
+ filter = filter ?? string.Empty;
+
var objectType = ConvertToObjectType(type);
if (objectType.HasValue)
{
diff --git a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs
index 2e44f1327b..afd1a6b61c 100644
--- a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs
+++ b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs
@@ -226,11 +226,11 @@ namespace Umbraco.Web.Models.Mapping
{
switch (entity)
{
- case ContentEntitySlim contentEntity:
- // NOTE: this case covers both content and media entities
- return contentEntity.ContentTypeIcon;
- case MemberEntitySlim memberEntity:
+ case IMemberEntitySlim memberEntity:
return memberEntity.ContentTypeIcon.IfNullOrWhiteSpace(Constants.Icons.Member);
+ case IContentEntitySlim contentEntity:
+ // NOTE: this case covers both content and media entities
+ return contentEntity.ContentTypeIcon;
}
return null;
diff --git a/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs
index 88960fb189..aa158799cb 100644
--- a/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs
+++ b/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs
@@ -380,8 +380,8 @@ namespace Umbraco.Web.Models.Mapping
.ToDictionary(x => x.Key, x => (IEnumerable)x.ToArray());
}
- private static string MapContentTypeIcon(EntitySlim entity)
- => entity is ContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null;
+ private static string MapContentTypeIcon(IEntitySlim entity)
+ => entity is IContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null;
private IEnumerable GetStartNodes(int[] startNodeIds, UmbracoObjectTypes objectType, string localizedKey, MapperContext context)
{
diff --git a/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs b/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs
index ac75fd831d..fd05f7cfbd 100644
--- a/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs
+++ b/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs
@@ -47,7 +47,7 @@ namespace Umbraco.Web.Trees
if (id == Constants.System.RootString)
{
//get all blueprint content types
- var contentTypeAliases = entities.Select(x => ((ContentEntitySlim) x).ContentTypeAlias).Distinct();
+ var contentTypeAliases = entities.Select(x => ((IContentEntitySlim) x).ContentTypeAlias).Distinct();
//get the ids
var contentTypeIds = Services.ContentTypeService.GetAllContentTypeIds(contentTypeAliases.ToArray()).ToArray();
@@ -75,7 +75,7 @@ namespace Umbraco.Web.Trees
var ct = Services.ContentTypeService.Get(intId.Result);
if (ct == null) return nodes;
- var blueprintsForDocType = entities.Where(x => ct.Alias == ((ContentEntitySlim) x).ContentTypeAlias);
+ var blueprintsForDocType = entities.Where(x => ct.Alias == ((IContentEntitySlim) x).ContentTypeAlias);
nodes.AddRange(blueprintsForDocType
.Select(entity =>
{