Fixes: U4-6099 cmsLanguageText.languageId needs to be a foreign key to the umbracoLanguage table

This commit is contained in:
Shannon
2015-07-02 17:19:42 +02:00
parent f0742c9d7c
commit f68cdf43e1
18 changed files with 122 additions and 60 deletions

View File

@@ -27,6 +27,7 @@ namespace Umbraco.Core
/// <summary>
/// The root id for all top level dictionary items
/// </summary>
[Obsolete("There is no dictionary root item id anymore, it is simply null")]
public const string DictionaryItemRootId = "41c7638d-f529-4bff-853e-59a0c2fb1bde";
}

View File

@@ -14,22 +14,22 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class DictionaryItem : Entity, IDictionaryItem
{
private Guid _parentId;
private Guid? _parentId;
private string _itemKey;
private IEnumerable<IDictionaryTranslation> _translations;
public DictionaryItem(string itemKey)
: this(new Guid(Constants.Conventions.Localization.DictionaryItemRootId), itemKey)
: this(null, itemKey)
{}
public DictionaryItem(Guid parentId, string itemKey)
public DictionaryItem(Guid? parentId, string itemKey)
{
_parentId = parentId;
_itemKey = itemKey;
_translations = new List<IDictionaryTranslation>();
}
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, Guid>(x => x.ParentId);
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, Guid?>(x => x.ParentId);
private static readonly PropertyInfo ItemKeySelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, string>(x => x.ItemKey);
private static readonly PropertyInfo TranslationsSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, IEnumerable<IDictionaryTranslation>>(x => x.Translations);
@@ -37,7 +37,7 @@ namespace Umbraco.Core.Models
/// Gets or Sets the Parent Id of the Dictionary Item
/// </summary>
[DataMember]
public Guid ParentId
public Guid? ParentId
{
get { return _parentId; }
set
@@ -95,11 +95,7 @@ namespace Umbraco.Core.Models
{
base.AddingEntity();
Key = Guid.NewGuid();
//If ParentId is not set we should default to the root parent id
if(ParentId == Guid.Empty)
_parentId = new Guid(Constants.Conventions.Localization.DictionaryItemRootId);
Key = Guid.NewGuid();
}
}

View File

@@ -12,7 +12,7 @@ namespace Umbraco.Core.Models
/// Gets or Sets the Parent Id of the Dictionary Item
/// </summary>
[DataMember]
Guid ParentId { get; set; }
Guid? ParentId { get; set; }
/// <summary>
/// Gets or sets the Key for the Dictionary Item

View File

@@ -19,7 +19,9 @@ namespace Umbraco.Core.Models.Rdbms
public Guid UniqueId { get; set; }
[Column("parent")]
public Guid Parent { get; set; }
[NullSetting(NullSetting = NullSettings.Null)]
[ForeignKey(typeof(DictionaryDto), Column = "id")]
public Guid? Parent { get; set; }
[Column("key")]
[Length(1000)]

View File

@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models.Rdbms
public int PrimaryKey { get; set; }
[Column("languageId")]
[ForeignKey(typeof(LanguageDto), Column = "id")]
public int LanguageId { get; set; }
[Column("UniqueId")]

View File

@@ -151,6 +151,13 @@ namespace Umbraco.Core.Persistence
_db.Update<UserDto>("SET id = @IdAfter WHERE id = @IdBefore AND userLogin = @Login", new { IdAfter = 0, IdBefore = 1, Login = "admin" });
}
//Loop through index statements and execute sql
foreach (var sql in indexSql)
{
int createdIndex = _db.Execute(new Sql(sql));
_logger.Info<Database>(string.Format("Create Index sql {0}:\n {1}", createdIndex, sql));
}
//Loop through foreignkey statements and execute sql
foreach (var sql in foreignSql)
{
@@ -158,12 +165,7 @@ namespace Umbraco.Core.Persistence
_logger.Info<Database>(string.Format("Create Foreign Key sql {0}:\n {1}", createdFk, sql));
}
//Loop through index statements and execute sql
foreach (var sql in indexSql)
{
int createdIndex = _db.Execute(new Sql(sql));
_logger.Info<Database>(string.Format("Create Index sql {0}:\n {1}", createdIndex, sql));
}
transaction.Complete();
}

View File

@@ -48,8 +48,8 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
{7, typeof (DataTypeDto)},
{8, typeof (DataTypePreValueDto)},
{9, typeof (DictionaryDto)},
{10, typeof (LanguageTextDto)},
{11, typeof (LanguageDto)},
{10, typeof (LanguageDto)},
{11, typeof (LanguageTextDto)},
{12, typeof (DomainDto)},
{13, typeof (LogDto)},
{14, typeof (MacroDto)},

View File

@@ -53,5 +53,32 @@ namespace Umbraco.Core.Persistence.Migrations
/// to ensure they are not executed twice.
/// </summary>
internal string Name { get; set; }
protected string GetQuotedValue(object val)
{
if (val == null) return "NULL";
var type = val.GetType();
switch (Type.GetTypeCode(type))
{
case TypeCode.Boolean:
return ((bool)val) ? "1" : "0";
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return val.ToString();
default:
return SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(val.ToString());
}
}
}
}

View File

@@ -44,7 +44,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
whereClauses.Add(string.Format("{0} {1} {2}",
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
item.Value == null ? "IS" : "=",
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
GetQuotedValue(item.Value)));
}
deleteItems.Add(string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteData,

View File

@@ -60,29 +60,6 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Insert.Expressions
return string.Join(",", insertItems);
}
private string GetQuotedValue(object val)
{
var type = val.GetType();
switch (Type.GetTypeCode(type))
{
case TypeCode.Boolean:
return ((bool) val) ? "1" : "0";
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return val.ToString();
default:
return SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(val.ToString());
}
}
}
}

View File

@@ -32,7 +32,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions
{
updateItems.Add(string.Format("{0} = {1}",
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
GetQuotedValue(item.Value)));
}
if (IsAllRows)
@@ -46,7 +46,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions
whereClauses.Add(string.Format("{0} {1} {2}",
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
item.Value == null ? "IS" : "=",
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
GetQuotedValue(item.Value)));
}
}
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.UpdateData,

View File

@@ -0,0 +1,58 @@
using System;
using System.Data;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZero
{
[Migration("7.3.0", 14, GlobalSettings.UmbracoMigrationName)]
public class AddForeignKeysForLanguageAndDictionaryTables : MigrationBase
{
public AddForeignKeysForLanguageAndDictionaryTables(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{
}
public override void Up()
{
var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
//if the FK doesn't exist
if (constraints.Any(x => x.Item1.InvariantEquals("cmsLanguageText") && x.Item2.InvariantEquals("umbracoLanguage") && x.Item3.InvariantEquals("FK_cmsLanguageText_umbracoLanguage_id")) == false)
{
//Somehow, a language text item might end up with a language Id of zero or one that no longer exists
//before we add the foreign key
foreach (var pk in Context.Database.Query<int>(
"SELECT cmsLanguageText.pk FROM cmsLanguageText WHERE cmsLanguageText.languageId NOT IN (SELECT umbracoLanguage.id FROM umbracoLanguage)"))
{
Delete.FromTable("cmsLanguageText").Row(new { pk = pk });
}
//now we need to create a foreign key
Create.ForeignKey("FK_cmsLanguageText_umbracoLanguage_id").FromTable("cmsLanguageText").ForeignColumn("languageId")
.ToTable("umbracoLanguage").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None);
Alter.Table("cmsDictionary").AlterColumn("parent").AsGuid().Nullable();
//set the parent to null if it equals the default dictionary item root id
foreach (var pk in Context.Database.Query<int>("SELECT pk FROM cmsDictionary WHERE parent NOT IN (SELECT id FROM cmsDictionary)"))
{
Update.Table("cmsDictionary").Set(new { parent = (Guid?)null }).Where(new { pk = pk });
}
Create.ForeignKey("FK_cmsDictionary_cmsDictionary_id").FromTable("cmsDictionary").ForeignColumn("parent")
.ToTable("cmsDictionary").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None);
}
}
public override void Down()
{
throw new System.NotImplementedException();
}
}
}

View File

@@ -103,12 +103,9 @@ namespace Umbraco.Core.Persistence.Repositories
return new List<string>();
}
/// <summary>
/// Returns the Top Level Parent Guid Id
/// </summary>
protected override Guid NodeObjectTypeId
{
get { return new Guid(Constants.Conventions.Localization.DictionaryItemRootId); }
get { throw new NotImplementedException(); }
}
#endregion

View File

@@ -18,7 +18,6 @@ namespace Umbraco.Core.Services
/// </summary>
public class LocalizationService : RepositoryService, ILocalizationService
{
private static readonly Guid RootParentId = new Guid(Constants.Conventions.Localization.DictionaryItemRootId);
[Obsolete("Use the constructors that specify all dependencies instead")]
public LocalizationService()
@@ -93,7 +92,7 @@ namespace Umbraco.Core.Services
}
}
var item = new DictionaryItem(parentId.HasValue ? parentId.Value : RootParentId, key);
var item = new DictionaryItem(parentId, key);
if (defaultValue.IsNullOrWhiteSpace() == false)
{
@@ -188,7 +187,7 @@ namespace Umbraco.Core.Services
{
using (var repository = RepositoryFactory.CreateDictionaryRepository(UowProvider.GetUnitOfWork()))
{
var query = Query<IDictionaryItem>.Builder.Where(x => x.ParentId == RootParentId);
var query = Query<IDictionaryItem>.Builder.Where(x => x.ParentId == null);
var items = repository.GetByQuery(query);
return items;

View File

@@ -381,6 +381,7 @@
<Compile Include="Persistence\Mappers\DomainMapper.cs" />
<Compile Include="Persistence\Mappers\MigrationEntryMapper.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\AddExternalLoginsTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\AddForeignKeysForLanguageAndDictionaryTables.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\AddMigrationTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\AddPublicAccessTables.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\AddUniqueIdPropertyTypeColumn.cs" />

View File

@@ -258,6 +258,7 @@ namespace Umbraco.Tests.Persistence
using (Transaction transaction = Database.GetTransaction())
{
DatabaseSchemaHelper.CreateTable<DictionaryDto>();
DatabaseSchemaHelper.CreateTable<LanguageDto>();
DatabaseSchemaHelper.CreateTable<LanguageTextDto>();
//transaction.Complete();

View File

@@ -179,7 +179,7 @@ namespace Umbraco.Tests.Services
Assert.Greater(item.Id, 0);
Assert.IsTrue(item.HasIdentity);
Assert.AreEqual(new Guid(Constants.Conventions.Localization.DictionaryItemRootId), item.ParentId);
Assert.IsFalse(item.ParentId.HasValue);
Assert.AreEqual("Testing123", item.ItemKey);
Assert.AreEqual(1, item.Translations.Count());
}
@@ -197,7 +197,7 @@ namespace Umbraco.Tests.Services
Assert.IsNotNull(item);
Assert.Greater(item.Id, 0);
Assert.IsTrue(item.HasIdentity);
Assert.AreEqual(new Guid(Constants.Conventions.Localization.DictionaryItemRootId), item.ParentId);
Assert.IsFalse(item.ParentId.HasValue);
Assert.AreEqual("Testing12345", item.ItemKey);
var allLangs = ServiceContext.LocalizationService.GetAllLanguages();
Assert.Greater(allLangs.Count(), 0);

View File

@@ -93,8 +93,8 @@ namespace umbraco.cms.businesslogic
[Obsolete("This is no longer used and will be removed from the codebase in future versions")]
public bool IsTopMostItem()
{
return _dictionaryItem.ParentId == new Guid(Constants.Conventions.Localization.DictionaryItemRootId);
{
return _dictionaryItem.ParentId.HasValue == false;
}
/// <summary>
@@ -105,9 +105,9 @@ namespace umbraco.cms.businesslogic
get
{
//EnsureCache();
if (_parent == null)
if (_parent == null && _dictionaryItem.ParentId.HasValue)
{
var p = ApplicationContext.Current.Services.LocalizationService.GetDictionaryItemById(_dictionaryItem.ParentId);
var p = ApplicationContext.Current.Services.LocalizationService.GetDictionaryItemById(_dictionaryItem.ParentId.Value);
if (p == null)
{