From 7fbda1dc7d4a2a58f1fdb52bf2ced9088287e9b7 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 4 Jul 2014 10:54:12 +1000 Subject: [PATCH] Fixes performance for Get(id) on ContentTypeRepository = much faster now, now to work on getall/query --- .../Repositories/ContentTypeRepository.cs | 173 ++++++++++++++---- ...Tests.cs => ContentTypeSqlMappingTests.cs} | 52 +++++- .../Services/ContentServicePerformanceTest.cs | 20 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 2 +- 4 files changed, 205 insertions(+), 42 deletions(-) rename src/Umbraco.Tests/Persistence/Querying/{PropertyTypeRelatorTests.cs => ContentTypeSqlMappingTests.cs} (57%) diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs index a3c4b19457..5e75387542 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.Caching; using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.Relators; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; @@ -47,47 +48,30 @@ namespace Umbraco.Core.Persistence.Repositories //NOTE: SQL call #1 - var dto = Database.Fetch(contentTypeSql).FirstOrDefault(); + IEnumerable> assocatedTemplates; + var contentType = ContentTypeQueries.MapContentType(id, Database, out assocatedTemplates); - //var dto = Database.Fetch( - // new AllowedContentTypeRelator().Map, - // contentTypeSql); - - if (dto == null) + if (contentType == null) return null; - var factory = new ContentTypeFactory(NodeObjectTypeId); - var contentType = factory.BuildEntity(dto); - //NOTE: SQL call #2 - contentType.AllowedContentTypes = GetAllowedContentTypeIds(id); - PropertyGroupCollection propGroups; PropertyTypeCollection propTypes; - ContentTypeQueries.PopulateGroupsAndProperties(id, Database, out propTypes, out propGroups); + ContentTypeQueries.MapGroupsAndProperties(id, Database, out propTypes, out propGroups); contentType.PropertyGroups = propGroups; - ((ContentType) contentType).PropertyTypes = propTypes; + ((ContentType)contentType).PropertyTypes = propTypes; - ////NOTE: SQL call #3 - //contentType.PropertyGroups = GetPropertyGroupCollection(id, contentType.CreateDate, contentType.UpdateDate); + //NOTE: SQL call #3++ + //SEE: http://issues.umbraco.org/issue/U4-5174 to fix this - ////NOTE: SQL call #4 - //((ContentType)contentType).PropertyTypes = GetPropertyTypeCollection(id, contentType.CreateDate, contentType.UpdateDate); + var templates = _templateRepository.GetAll(assocatedTemplates.Select(x => x.Item1).ToArray()); + contentType.AllowedTemplates = templates.ToArray(); - //NOTE: SQL call #5 + //NOTE: SQL call #5++ + //TODO: Fix this part up, surely we can include it in the first sql call - var templates = Database.Fetch("WHERE contentTypeNodeId = @Id", new { Id = id }); - if(templates.Any()) - { - //NOTE: SQL call #6++ - - contentType.AllowedTemplates = templates.Select(template => _templateRepository.Get(template.TemplateNodeId)).ToList(); - } - - //NOTE: SQL call #7 - - var list = Database.Fetch("WHERE childContentTypeId = @Id", new { Id = id}); + var list = Database.Fetch("WHERE childContentTypeId = @Id", new { Id = id }); foreach (var contentTypeDto in list) { bool result = contentType.AddContentType(Get(contentTypeDto.ParentId)); @@ -150,15 +134,14 @@ namespace Umbraco.Core.Persistence.Repositories protected override Sql GetBaseQuery(bool isCount) { var sql = new Sql(); + sql.Select(isCount ? "COUNT(*)" : "*") .From() .RightJoin() .On(left => left.NodeId, right => right.ContentTypeNodeId) .InnerJoin() .On(left => left.NodeId, right => right.NodeId) - //.LeftJoin() - //.On(left => left.AllowedId, right => right.NodeId) - .Where(x => x.NodeObjectType == NodeObjectTypeId); + .Where(x => x.NodeObjectType == new Guid(Constants.ObjectTypes.DocumentType)); return sql; } @@ -303,7 +286,129 @@ namespace Umbraco.Core.Persistence.Repositories internal static class ContentTypeQueries { - public static void PopulateGroupsAndProperties(int contentTypeId, Database db, out PropertyTypeCollection propertyTypeCollection, out PropertyGroupCollection propertyGroupCollection) + public static IContentType MapContentType(int contentTypeId, Database db, out IEnumerable> associatedTemplates) + { + var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId, + cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, + cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb, + AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias, + umbracoNode.createDate as nCreateDate, umbracoNode.[level] as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser, + umbracoNode.parentID as nParentId, umbracoNode.[path] as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode.[text] as nName, umbracoNode.trashed as nTrashed, + umbracoNode.uniqueID as nUniqueId, + Template.alias as tAlias, Template.nodeId as tId,Template.text as tText + FROM cmsDocumentType + RIGHT JOIN cmsContentType + ON cmsContentType.nodeId = cmsDocumentType.contentTypeNodeId + INNER JOIN umbracoNode + ON cmsContentType.nodeId = umbracoNode.id + LEFT JOIN ( + SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder + FROM cmsContentTypeAllowedContentType + INNER JOIN cmsContentType + ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId + ) AllowedTypes + ON AllowedTypes.Id = cmsContentType.nodeId + LEFT JOIN ( + SELECT * FROM cmsTemplate + INNER JOIN umbracoNode + ON cmsTemplate.nodeId = umbracoNode.id + ) as Template + ON Template.nodeId = cmsDocumentType.templateNodeId + WHERE (umbracoNode.nodeObjectType = @nodeObjectType) + AND (umbracoNode.id = @contentTypeId) + ORDER BY cmsDocumentType.IsDefault DESC"; + + var result = db.Fetch(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), contentTypeId = contentTypeId }); + + //first we want to get the main content type data this is 1 : 1 with umbraco node data + var ct = result + .Select(x => new { x.ctPk, x.ctId, x.ctAlias, x.ctAllowAtRoot, x.ctDesc, x.ctIcon, x.ctIsContainer, x.ctThumb, x.nName, x.nCreateDate, x.nLevel, x.nObjectType, x.nUser, x.nParentId, x.nPath, x.nSortOrder, x.nTrashed, x.nUniqueId }) + .DistinctBy(x => (int)x.ctId) + .FirstOrDefault(); + + if (ct == null) + { + associatedTemplates = null; + return null; + } + + //get the unique list of associated templates + var defaultTemplates = result + //use a tuple so that distinct checks both values + .Select(x => new Tuple(x.dtIsDefault, x.dtTemplateId )) + .Where(x => x.Item1.HasValue && x.Item2.HasValue) + .Distinct() + .ToArray(); + //if there isn't one set to default explicitly, we'll pick the first one + var defaultTemplate = defaultTemplates.FirstOrDefault(x => x.Item1.Value) + ?? defaultTemplates.FirstOrDefault(); + + var dtDto = new DocumentTypeDto + { + //create the content type dto + ContentTypeDto = new ContentTypeDto + { + Alias = ct.ctAlias, + AllowAtRoot = ct.ctAllowAtRoot, + Description = ct.ctDesc, + Icon = ct.ctIcon, + IsContainer = ct.ctIsContainer, + NodeId = ct.ctId, + PrimaryKey = ct.ctPk, + Thumbnail = ct.ctThumb, + //map the underlying node dto + NodeDto = new NodeDto + { + CreateDate = ct.nCreateDate, + Level = (short)ct.nLevel, + NodeId = ct.ctId, + NodeObjectType = ct.nObjectType, + ParentId = ct.nParentId, + Path = ct.nPath, + SortOrder = ct.nSortOrder, + Text = ct.nName, + Trashed = ct.nTrashed, + UniqueId = ct.nUniqueId, + UserId = ct.nUser + } + }, + ContentTypeNodeId = ct.ctId, + IsDefault = defaultTemplate != null, + TemplateNodeId = defaultTemplate != null ? defaultTemplate.Item2.Value : 0 + }; + + // We will return a subset of the associated template - alias, id, name + // TODO: See: http://issues.umbraco.org/issue/U4-5174 + + //next, we'll get the template subset + associatedTemplates = result + .Select(x => new Tuple(x.tId, x.tAlias, x.tText)) + .Where(x => x.Item1.HasValue) + .Select(x => new Tuple(x.Item1.Value, x.Item2, x.Item3)) + .Distinct() + .ToArray(); + + + //now create the content type object + + var factory = new ContentTypeFactory(new Guid(Constants.ObjectTypes.DocumentType)); + var contentType = factory.BuildEntity(dtDto); + + //map the allowed content types + contentType.AllowedContentTypes = result + //use tuple so we can use distinct on all vals + .Select(x => new Tuple(x.ctaAllowedId, x.ctaSortOrder, x.ctaAlias)) + .Where(x => x.Item1.HasValue && x.Item2.HasValue && x.Item3 != null) + .Distinct() + .Select(x => new ContentTypeSort(new Lazy(() => x.Item1.Value), x.Item2.Value, x.Item3)) + .ToList(); + + return contentType; + } + + + + public static void MapGroupsAndProperties(int contentTypeId, Database db, out PropertyTypeCollection propertyTypeCollection, out PropertyGroupCollection propertyGroupCollection) { // first part Gets all property groups including property type data even when no property type exists on the group // second part Gets all property types including ones that are not on a group @@ -323,7 +428,7 @@ namespace Umbraco.Core.Persistence.Repositories INNER JOIN cmsDataType as DT ON PT.dataTypeId = DT.nodeId ) as PT - ON PG.[id] = PT.ptGroupId + ON PT.ptGroupId = PG.id WHERE (PG.contenttypeNodeId = @contentTypeId) UNION diff --git a/src/Umbraco.Tests/Persistence/Querying/PropertyTypeRelatorTests.cs b/src/Umbraco.Tests/Persistence/Querying/ContentTypeSqlMappingTests.cs similarity index 57% rename from src/Umbraco.Tests/Persistence/Querying/PropertyTypeRelatorTests.cs rename to src/Umbraco.Tests/Persistence/Querying/ContentTypeSqlMappingTests.cs index 089671a780..5150383e7d 100644 --- a/src/Umbraco.Tests/Persistence/Querying/PropertyTypeRelatorTests.cs +++ b/src/Umbraco.Tests/Persistence/Querying/ContentTypeSqlMappingTests.cs @@ -19,6 +19,48 @@ namespace Umbraco.Tests.Persistence.Querying [TestFixture] public class ContentTypeSqlMappingTests : BaseDatabaseFactoryTest { + [Test] + public void Can_Map_Content_Type_Templates_And_Allowed_Types() + { + using (var transaction = DatabaseContext.Database.GetTransaction()) + { + DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("umbracoNode")))); + DatabaseContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55554, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,55554", SortOrder = 1, UniqueId = new Guid("87D1EAB6-AB27-4852-B3DF-DE8DBA4A1AA0"), Text = "Template 1", NodeObjectType = new Guid(Constants.ObjectTypes.Template), CreateDate = DateTime.Now }); + DatabaseContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55555, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,55555", SortOrder = 1, UniqueId = new Guid("3390BDF4-C974-4211-AA95-3812A8CE7C46"), Text = "Template 2", NodeObjectType = new Guid(Constants.ObjectTypes.Template), CreateDate = DateTime.Now }); + DatabaseContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99997, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1,99997", SortOrder = 0, UniqueId = new Guid("BB3241D5-6842-4EFA-A82A-5F56885CF528"), Text = "Test Content Type 1", NodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), CreateDate = DateTime.Now }); + DatabaseContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99998, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1,99998", SortOrder = 0, UniqueId = new Guid("EEA66B06-302E-49BA-A8B2-EDF07248BC59"), Text = "Test Content Type 2", NodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), CreateDate = DateTime.Now }); + DatabaseContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("C45CC083-BB27-4C1C-B448-6F703CC9B799"), Text = "Test Content Type 2", NodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), CreateDate = DateTime.Now }); + DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("umbracoNode")))); + + DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsTemplate")))); + DatabaseContext.Database.Insert("cmsTemplate", "pk", false, new TemplateDto { NodeId = 55554, Alias = "testTemplate1", Design = "", Master = null, PrimaryKey = 22221}); + DatabaseContext.Database.Insert("cmsTemplate", "pk", false, new TemplateDto { NodeId = 55555, Alias = "testTemplate2", Design = "", Master = null, PrimaryKey = 22222 }); + DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsTemplate")))); + + DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsContentType")))); + DatabaseContext.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88887, NodeId = 99997, Alias = "TestContentType1", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); + DatabaseContext.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99998, Alias = "TestContentType2", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); + DatabaseContext.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88889, NodeId = 99999, Alias = "TestContentType3", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); + DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsContentType")))); + + DatabaseContext.Database.Insert(new DocumentTypeDto { ContentTypeNodeId = 99997, IsDefault = true, TemplateNodeId = 55555 }); + DatabaseContext.Database.Insert(new DocumentTypeDto { ContentTypeNodeId = 99997, IsDefault = false, TemplateNodeId = 55554 }); + + DatabaseContext.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99998, Id = 99997, SortOrder = 1 }); + DatabaseContext.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99999, Id = 99997, SortOrder = 2}); + + transaction.Complete(); + } + + IEnumerable> assocatedTemplates; + var contentType = ContentTypeRepository.ContentTypeQueries.MapContentType(99997, DatabaseContext.Database, out assocatedTemplates); + + Assert.IsNotNull(contentType); + Assert.AreEqual(2, contentType.AllowedContentTypes.Count()); + Assert.AreEqual(2, assocatedTemplates.Count()); + + } + [Test] public void Can_Map_All_Property_Groups_And_Types() { @@ -26,17 +68,17 @@ namespace Umbraco.Tests.Persistence.Querying { DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("umbracoNode")))); DatabaseContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55555, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,55555", SortOrder = 1, UniqueId = new Guid("3390BDF4-C974-4211-AA95-3812A8CE7C46"), Text = "Test Data Type", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - DatabaseContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1,2222", SortOrder = 0, UniqueId = new Guid("129241F0-D24E-4FC3-92D1-BC2D48B7C431"), Text = "Test Content Type", NodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), CreateDate = DateTime.Now }); + DatabaseContext.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("129241F0-D24E-4FC3-92D1-BC2D48B7C431"), Text = "Test Content Type", NodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), CreateDate = DateTime.Now }); DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("umbracoNode")))); DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsDataType")))); DatabaseContext.Database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 44444, DataTypeId = 55555, PropertyEditorAlias = Constants.PropertyEditors.TextboxAlias, DbType = "Nvarchar" }); DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsDataType")))); - + DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsContentType")))); DatabaseContext.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99999, Alias = "TestContentType", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsContentType")))); - + DatabaseContext.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsPropertyTypeGroup")))); DatabaseContext.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77776, ContentTypeNodeId = 99999, Text = "Group1", SortOrder = 1 }); DatabaseContext.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77777, ContentTypeNodeId = 99999, Text = "Group2", SortOrder = 2 }); @@ -59,7 +101,7 @@ namespace Umbraco.Tests.Persistence.Querying PropertyTypeCollection propTypeCollection; PropertyGroupCollection propGroupCollection; - ContentTypeRepository.ContentTypeQueries.PopulateGroupsAndProperties(99999, DatabaseContext.Database, out propTypeCollection, out propGroupCollection); + ContentTypeRepository.ContentTypeQueries.MapGroupsAndProperties(99999, DatabaseContext.Database, out propTypeCollection, out propGroupCollection); Assert.AreEqual(4, propGroupCollection.Count); Assert.AreEqual(2, propGroupCollection["Group1"].PropertyTypes.Count); @@ -72,7 +114,7 @@ namespace Umbraco.Tests.Persistence.Querying Assert.IsTrue(propGroupCollection["Group3"].PropertyTypes.Contains("property6")); Assert.IsTrue(propGroupCollection["Group3"].PropertyTypes.Contains("property7")); Assert.AreEqual(0, propGroupCollection["Group4"].PropertyTypes.Count); - + Assert.AreEqual(1, propTypeCollection.Count); Assert.IsTrue(propTypeCollection.Contains("property5")); diff --git a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs index d9c7a6de74..3855dc8e02 100644 --- a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs +++ b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs @@ -40,10 +40,26 @@ namespace Umbraco.Tests.Services //NOTE: Doing this the old 1 by 1 way and based on the results of the ContentServicePerformanceTest.Retrieving_All_Content_In_Site // the old way takes 143795ms, the new above way takes: 14249ms that is a 90% savings of processing and sql calls! - var contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "test1"); + var contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "test1"); var contentType2 = MockedContentTypes.CreateTextpageContentType("test2", "test2"); - var contentType3 = MockedContentTypes.CreateTextpageContentType("test3", "test3"); + var contentType3 = MockedContentTypes.CreateTextpageContentType("test3", "test3"); ServiceContext.ContentTypeService.Save(new[] {contentType1, contentType2, contentType3}); + contentType1.AllowedContentTypes = new[] + { + new ContentTypeSort(new Lazy(() => contentType2.Id), 0, contentType2.Alias), + new ContentTypeSort(new Lazy(() => contentType3.Id), 1, contentType3.Alias) + }; + contentType2.AllowedContentTypes = new[] + { + new ContentTypeSort(new Lazy(() => contentType1.Id), 0, contentType1.Alias), + new ContentTypeSort(new Lazy(() => contentType3.Id), 1, contentType3.Alias) + }; + contentType3.AllowedContentTypes = new[] + { + new ContentTypeSort(new Lazy(() => contentType1.Id), 0, contentType1.Alias), + new ContentTypeSort(new Lazy(() => contentType2.Id), 1, contentType2.Alias) + }; + ServiceContext.ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 }); var roots = MockedContent.CreateTextpageContent(contentType1, -1, 10); ServiceContext.ContentService.Save(roots); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 8c0609c1e0..c4a6a7ce41 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -298,7 +298,7 @@ - +