diff --git a/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs b/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs index f87930269a..25ca43f918 100644 --- a/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs @@ -45,6 +45,7 @@ namespace Umbraco.Core.Persistence.Dtos /// [Column("fallbackLanguageId")] [ForeignKey(typeof(LanguageDto), Column = "id")] + [Index(IndexTypes.NonClustered)] [NullSetting(NullSetting = NullSettings.Null)] public int? FallbackLanguageId { get; set; } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs index af5d28c18e..271e084969 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs @@ -177,7 +177,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override void PersistDeletedItem(ILanguage entity) { - //we need to validate that we can delete this language + // We need to validate that we can delete this language if (entity.IsDefaultVariantLanguage) throw new InvalidOperationException($"Cannot delete the default language ({entity.IsoCode})"); @@ -185,9 +185,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (count == 1) throw new InvalidOperationException($"Cannot delete the default language ({entity.IsoCode})"); + // We need to remove any references to the language if it's being used as a fall-back from other ones + Database.Execute(Sql().Update(u => u.Set(x => x.FallbackLanguageId, null)).Where(x => x.FallbackLanguageId == entity.Id)); + base.PersistDeletedItem(entity); - //Clear the cache entries that exist by key/iso + // Clear the cache entries that exist by key/iso IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(entity.IsoCode)); IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey(entity.CultureName)); } diff --git a/src/Umbraco.Core/Services/Implement/LocalizationService.cs b/src/Umbraco.Core/Services/Implement/LocalizationService.cs index 663ecf586c..e63a3cbdbb 100644 --- a/src/Umbraco.Core/Services/Implement/LocalizationService.cs +++ b/src/Umbraco.Core/Services/Implement/LocalizationService.cs @@ -393,8 +393,7 @@ namespace Umbraco.Core.Services.Implement return; } - //NOTE: There isn't any constraints in the db, so possible references aren't deleted - + // NOTE: Other than the fall-back language, there aren't any other constraints in the db, so possible references aren't deleted _languageRepository.Delete(language); deleteEventArgs.CanCancel = false; diff --git a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs index a63bf5e08d..ed82d03c6e 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs @@ -318,6 +318,30 @@ namespace Umbraco.Tests.Persistence.Repositories } } + [Test] + public void Can_Perform_Delete_On_LanguageRepository_With_Language_Used_As_Fallback() + { + // Arrange + var provider = TestObjects.GetScopeProvider(Logger); + using (var scope = provider.CreateScope()) + { + // Add language to delete as a fall-back language to another one + var repository = CreateRepository(provider); + var languageToFallbackFrom = repository.Get(5); + languageToFallbackFrom.FallbackLanguageId = 1; + repository.Save(languageToFallbackFrom); + + // Act + var languageToDelete = repository.Get(1); + repository.Delete(languageToDelete); + + var exists = repository.Exists(1); + + // Assert + Assert.That(exists, Is.False); + } + } + [Test] public void Can_Perform_Exists_On_LanguageRepository() { diff --git a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs b/src/Umbraco.Tests/Services/LocalizationServiceTests.cs index 033fa08d4a..ff5aa8edc9 100644 --- a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs +++ b/src/Umbraco.Tests/Services/LocalizationServiceTests.cs @@ -192,6 +192,20 @@ namespace Umbraco.Tests.Services Assert.Null(language); } + [Test] + public void Can_Delete_Language_Used_As_Fallback() + { + var danish = ServiceContext.LocalizationService.GetLanguageByIsoCode("da-DK"); + var norwegian = new Language("nb-NO") { CultureName = "Norwegian", FallbackLanguageId = danish.Id }; + ServiceContext.LocalizationService.Save(norwegian, 0); + var languageId = danish.Id; + + ServiceContext.LocalizationService.Delete(danish); + + var language = ServiceContext.LocalizationService.GetLanguageById(languageId); + Assert.Null(language); + } + [Test] public void Can_Create_DictionaryItem_At_Root() {