diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index 18027bcc1b..7aa8b707be 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -662,6 +662,26 @@ namespace Umbraco.Core.Persistence return sql.Select(sql.GetColumns(columnExpressions: fields)); } + /// + /// Creates a SELECT DISTINCT Sql statement. + /// + /// The type of the DTO to select. + /// The origin sql. + /// Expressions indicating the columns to select. + /// The Sql statement. + /// + /// If is empty, all columns are selected. + /// + public static Sql SelectDistinct(this Sql sql, params Expression>[] fields) + { + if (sql == null) throw new ArgumentNullException(nameof(sql)); + var columns = sql.GetColumns(columnExpressions: fields); + sql.Append("SELECT DISTINCT " + string.Join(", ", columns)); + return sql; + } + + //this.Append("SELECT " + string.Join(", ", columns), new object[0]); + /// /// Creates a SELECT Sql statement. /// diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 055ed7ae74..662254d1ee 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -809,7 +809,7 @@ AND umbracoNode.id <> @id", var targetLanguageIdS = targetLanguageId.HasValue ? targetLanguageId.ToString() : "NULL"; var sqlSelectTagsToInsert = Sql() - .Select(x => x.Text, x => x.Group) + .SelectDistinct(x => x.Text, x => x.Group) .Append(", " + targetLanguageIdS) .From(); @@ -840,7 +840,7 @@ AND umbracoNode.id <> @id", // and group, but for the target language var sqlSelectRelationsToInsert = Sql() - .Select(x => x.NodeId, x => x.PropertyTypeId) + .SelectDistinct(x => x.NodeId, x => x.PropertyTypeId) .AndSelect("otag", x => x.Id) .From() .InnerJoin().On((rel, tag) => rel.TagId == tag.Id) diff --git a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs index 196af5c0bd..8f66e98b76 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs @@ -256,6 +256,53 @@ namespace Umbraco.Tests.Services Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); } + [Test] + public void TagsCanBecomeInvariant2() + { + var languageService = ServiceContext.LocalizationService; + languageService.Save(new Language("fr-FR")); // en-US is already there + + var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + + var contentService = ServiceContext.ContentService; + var contentTypeService = ServiceContext.ContentTypeService; + var tagService = ServiceContext.TagService; + var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); + PropertyType propertyType; + contentType.PropertyGroups.First().PropertyTypes.Add( + propertyType = new PropertyType("test", ValueStorageType.Ntext, "tags") + { + DataTypeId = 1041, + Variations = ContentVariation.Culture + }); + contentType.Variations = ContentVariation.Culture; + contentTypeService.Save(contentType); + + IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + content1.SetCultureName("name-fr", "fr-FR"); + content1.SetCultureName("name-en", "en-US"); + content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags("tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + contentService.SaveAndPublish(content1); + + IContent content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + content2.SetCultureName("name-fr", "fr-FR"); + content2.SetCultureName("name-en", "en-US"); + content2.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content2.AssignTags("tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + contentService.SaveAndPublish(content2); + + //// pretend we already have invariant values + //using (var scope = ScopeProvider.CreateScope()) + //{ + // scope.Database.Execute("INSERT INTO [cmsTags] ([tag], [group], [languageId]) SELECT DISTINCT [tag], [group], NULL FROM [cmsTags] WHERE [languageId] IS NOT NULL"); + //} + + // this should work + propertyType.Variations = ContentVariation.Nothing; + Assert.DoesNotThrow(() => contentTypeService.Save(contentType)); + } + [Test] public void TagsCanBecomeInvariantByPropertyType() {