From 7a24f6dc59fdfd51f1db1d52d0d15ab961fbc206 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 9 Jan 2026 12:00:59 +0100 Subject: [PATCH 1/4] Remove ColumnProperty.Null if primary key is set. --- ...nProvider_GetColumns_DefaultValues_Tests.cs | 4 ++++ ...iteTransformationProvider_AddColumnTests.cs | 18 ++++++++++++++++++ .../SQLite/SQLiteColumnPropertiesMapper.cs | 17 ----------------- .../SQLite/SQLiteTransformationProvider.cs | 5 +++++ 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs index 33c385a8..03c60f2b 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs @@ -33,6 +33,7 @@ public void GetColumns_DefaultValues_Succeeds() const string decimalColumnName1 = "decimalcolumn"; const string guidColumnName1 = "guidcolumn1"; const string booleanColumnName1 = "booleancolumn1"; + const string booleanColumnName2 = "booleancolumn2"; const string int32ColumnName1 = "int32column1"; const string int64ColumnName1 = "int64column1"; const string int64ColumnName2 = "int64column2"; @@ -50,6 +51,7 @@ public void GetColumns_DefaultValues_Succeeds() // other boolean default values are tested in another test new Column(booleanColumnName1, DbType.Boolean, true), + new Column(booleanColumnName2, DbType.Boolean, false), new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), @@ -69,6 +71,7 @@ public void GetColumns_DefaultValues_Succeeds() var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); + var booleanColumn2 = columns.Single(x => x.Name.Equals(booleanColumnName2, StringComparison.OrdinalIgnoreCase)); var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); @@ -82,6 +85,7 @@ public void GetColumns_DefaultValues_Succeeds() Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(booleanColumn2.DefaultValue, Is.False); Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs index 6eb4d004..2efabf5d 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -58,4 +58,22 @@ public void AddColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() Assert.That(indexAfter.Name, Is.EqualTo(indexName)); CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); } + + [Test] + public void AddColumn_HavingNullInPrimaryKey_Succeds() + { + // Arrange/Act + Provider.ExecuteNonQuery("CREATE TABLE Common_Language (LanguageID TEXT PRIMARY KEY)"); + + Provider.AddColumn("Common_Language", "Enabled", DbType.Boolean); + + var tableInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo("Common_Language"); + var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Language"); + + var columnProperty = tableInfo.Columns.Single(x => x.Name == "LanguageID").ColumnProperty; + var hasNull = columnProperty.IsSet(ColumnProperty.Null); + + // Assert + Assert.That(hasNull, Is.False); + } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs index f8c3d72d..ddf2a078 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using DotNetProjects.Migrator.Framework; @@ -22,22 +21,6 @@ protected override void AddNull(Column column, List vals) } } - protected override void AddNotNull(Column column, List vals) - { - var isPrimaryKeySelected = PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey); - var isNullSelected = PropertySelected(column.ColumnProperty, ColumnProperty.Null); - var isNotNullSelected = PropertySelected(column.ColumnProperty, ColumnProperty.NotNull); - - if (isNullSelected && isPrimaryKeySelected) - { - throw new Exception("This is currently not supported by the migrator see issue #44. You need to use NOT NULL for a PK column."); - } - - if (isNotNullSelected || isPrimaryKeySelected) - { - AddValueIfSelected(column, ColumnProperty.NotNull, vals); - } - } protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) { diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 422e7724..555ed608 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1213,6 +1213,11 @@ public override Column[] GetColumns(string tableName) if (pragmaTableInfoItem.Pk > 0) { column.ColumnProperty |= ColumnProperty.PrimaryKey; + + if (column.ColumnProperty.IsSet(ColumnProperty.Null)) + { + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Null); + } } var indexListItems = GetPragmaIndexListItems(tableName); From 0128df7982f4b3ecf4c8271bd36968afc87b8fc5 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 9 Jan 2026 12:06:00 +0100 Subject: [PATCH 2/4] Added INT NOT NULL PRIMARY KEY test (AddColumn) --- ...iteTransformationProvider_AddColumnTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs index 2efabf5d..736de27f 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -76,4 +76,22 @@ public void AddColumn_HavingNullInPrimaryKey_Succeds() // Assert Assert.That(hasNull, Is.False); } + + [Test] + public void AddColumn_HavingNotNullInPrimaryKey_Succeds() + { + // Arrange/Act + Provider.ExecuteNonQuery("CREATE TABLE Common_Language (LanguageID INT NOT NULL PRIMARY KEY)"); + + Provider.AddColumn("Common_Language", "Enabled", DbType.Boolean); + + var tableInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo("Common_Language"); + var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Language"); + + var columnProperty = tableInfo.Columns.Single(x => x.Name == "LanguageID").ColumnProperty; + var hasNull = columnProperty.IsSet(ColumnProperty.Null); + + // Assert + Assert.That(hasNull, Is.False); + } } From 8d77198cf30491c386d020fba9ffae851a6b7210 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 9 Jan 2026 12:18:26 +0100 Subject: [PATCH 3/4] Update --- .../Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs index ddf2a078..40b59832 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs @@ -21,6 +21,13 @@ protected override void AddNull(Column column, List vals) } } + protected override void AddNotNull(Column column, List vals) + { + if (column.IsIdentity) + { + AddValueIfSelected(column, ColumnProperty.NotNull, vals); + } + } protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) { From 635536e93a0242252c96e50223896f059a0fdfaf Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 9 Jan 2026 13:30:51 +0100 Subject: [PATCH 4/4] Updated Primary Key behaviour --- ...teTransformationProvider_AddColumnTests.cs | 25 ++++++++++++++++--- ...iteTransformationProvider_AddTableTests.cs | 5 ++-- ...eTransformationProvider_GetColumnsTests.cs | 7 +++--- ...ionProvider_PropertyColumnIdentityTests.cs | 3 ++- .../SQLite/SQLiteColumnPropertiesMapper.cs | 2 +- .../SQLite/SQLiteTransformationProvider.cs | 10 +++++--- 6 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs index 736de27f..b9d32893 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -60,7 +60,7 @@ public void AddColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() } [Test] - public void AddColumn_HavingNullInPrimaryKey_Succeds() + public void AddColumn_HavingNullInPrimaryKey_HasNULLAfterAddAnotherColumn() { // Arrange/Act Provider.ExecuteNonQuery("CREATE TABLE Common_Language (LanguageID TEXT PRIMARY KEY)"); @@ -71,10 +71,26 @@ public void AddColumn_HavingNullInPrimaryKey_Succeds() var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Language"); var columnProperty = tableInfo.Columns.Single(x => x.Name == "LanguageID").ColumnProperty; - var hasNull = columnProperty.IsSet(ColumnProperty.Null); // Assert - Assert.That(hasNull, Is.False); + Assert.That(script, Does.Contain("LanguageID TEXT NULL PRIMARY KEY")); + } + + [Test] + public void AddColumn_HavingNullInPrimaryKey_HasNOTNULLAfterAddAnotherColumn() + { + // Arrange/Act + Provider.ExecuteNonQuery("CREATE TABLE Common_Language (LanguageID TEXT NOT NULL PRIMARY KEY)"); + + Provider.AddColumn("Common_Language", "Enabled", DbType.Boolean); + + var tableInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo("Common_Language"); + var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Language"); + + var columnProperty = tableInfo.Columns.Single(x => x.Name == "LanguageID").ColumnProperty; + + // Assert + Assert.That(script, Does.Contain("LanguageID TEXT NOT NULL PRIMARY KEY")); } [Test] @@ -91,7 +107,8 @@ public void AddColumn_HavingNotNullInPrimaryKey_Succeds() var columnProperty = tableInfo.Columns.Single(x => x.Name == "LanguageID").ColumnProperty; var hasNull = columnProperty.IsSet(ColumnProperty.Null); - // Assert + // Assert + Assert.That(script, Does.Contain("LanguageID INTEGER NOT NULL PRIMARY KEY")); Assert.That(hasNull, Is.False); } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 269c2661..2b9eee06 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -87,10 +87,9 @@ public void AddTable_SinglePrimaryKey_ContainsNull() // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY, Column2 INTEGER NOT NULL)")); - var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); - Assert.That(pragmaTableInfos.All(x => x.NotNull), Is.True); + // In SQLite an INTEGER PRIMARY KEY column is NOT NULL implicitly (see insert asserts above) + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER PRIMARY KEY, Column2 INTEGER NOT NULL)")); var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index 992e5a4c..9b7c576a 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -63,8 +63,7 @@ public void GetColumns_Primary_ColumnPropertyOk() // Assert Assert.That(columns.Single().ColumnProperty, Is.EqualTo(ColumnProperty.NotNull | - ColumnProperty.Identity | - ColumnProperty.PrimaryKey)); + ColumnProperty.PrimaryKeyWithIdentity)); } [Test] @@ -82,8 +81,8 @@ public void GetColumns_PrimaryKeyOnTwoColumns_BothColumnsHavePrimaryKeyAndAreNot var columns = Provider.GetColumns(tableName); // Assert - Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.Null)); - Assert.That(columns[1].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.Null)); + Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull)); + Assert.That(columns[1].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull)); } [Test] diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs index 1034e155..ad841b31 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs @@ -25,6 +25,7 @@ public void AddPrimaryIdentity_Succeeds() var sql = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(testTableName); - Assert.That(sql, Does.Contain("Color1 INTEGER NOT NULL PRIMARY KEY")); + // NOT NULL implicitly set in SQLite + Assert.That(sql, Does.Contain("Color1 INTEGER PRIMARY KEY")); } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs index 40b59832..442a7834 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs @@ -23,7 +23,7 @@ protected override void AddNull(Column column, List vals) protected override void AddNotNull(Column column, List vals) { - if (column.IsIdentity) + if (column.ColumnProperty.HasFlag(ColumnProperty.NotNull)) { AddValueIfSelected(column, ColumnProperty.NotNull, vals); } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 555ed608..b3fb46a2 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1212,12 +1212,16 @@ public override Column[] GetColumns(string tableName) if (pragmaTableInfoItem.Pk > 0) { - column.ColumnProperty |= ColumnProperty.PrimaryKey; - - if (column.ColumnProperty.IsSet(ColumnProperty.Null)) + if (new[] { DbType.UInt16, DbType.UInt32, DbType.UInt64, DbType.Int16, DbType.Int32, DbType.Int64 }.Contains(column.Type)) { + column.ColumnProperty |= ColumnProperty.PrimaryKey; + column.ColumnProperty |= ColumnProperty.NotNull; column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Null); } + else + { + column.ColumnProperty |= ColumnProperty.PrimaryKey; + } } var indexListItems = GetPragmaIndexListItems(tableName);