fix #5897 - allow SQLite to drop columns, remove deprecated columns, and handle upgrade logic

This commit is contained in:
sbwalker
2025-12-19 09:03:44 -05:00
parent 1682a123b4
commit a10575bfc3
13 changed files with 105 additions and 34 deletions

View File

@@ -31,12 +31,15 @@ namespace Oqtane.Database.Sqlite
public override void DropColumn(MigrationBuilder builder, string name, string table) public override void DropColumn(MigrationBuilder builder, string name, string table)
{ {
// not implemented as SQLite does not support dropping columns // SQLite supports dropping columns starting with version 3.35.0 but EF Core does not implement it yet
// note that a column cannot be dropped if it has a UNIQUE constraint, is part of a PRIMARY KEY, is indexed, or is referenced by other parts of the schema
builder.Sql($"ALTER TABLE {table} DROP COLUMN {name};");
} }
public override void AlterStringColumn(MigrationBuilder builder, string name, string table, int length, bool nullable, bool unicode, string index) public override void AlterStringColumn(MigrationBuilder builder, string name, string table, int length, bool nullable, bool unicode, string index)
{ {
// not implemented as SQLite does not support altering columns // not implemented as SQLite does not support altering columns
// note that column length does not need to be modified as SQLite uses a TEXT type which utilizes variable length strings
} }
public override string ConcatenateSql(params string[] values) public override string ConcatenateSql(params string[] values)

View File

@@ -16,15 +16,18 @@ namespace Oqtane.Migrations.Tenant
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase); if (ActiveDatabase.Name != "Sqlite")
folderEntityBuilder.DropColumn("DeletedBy"); {
folderEntityBuilder.DropColumn("DeletedOn"); var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase);
folderEntityBuilder.DropColumn("IsDeleted"); folderEntityBuilder.DropColumn("DeletedBy");
folderEntityBuilder.DropColumn("DeletedOn");
folderEntityBuilder.DropColumn("IsDeleted");
var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase); var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase);
fileEntityBuilder.DropColumn("DeletedBy"); fileEntityBuilder.DropColumn("DeletedBy");
fileEntityBuilder.DropColumn("DeletedOn"); fileEntityBuilder.DropColumn("DeletedOn");
fileEntityBuilder.DropColumn("IsDeleted"); fileEntityBuilder.DropColumn("IsDeleted");
}
} }
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)

View File

@@ -16,7 +16,7 @@ namespace Oqtane.Migrations.Tenant
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
// IsDeleted columns were removed in 3.2.2 however SQLite does not support column removal so they had to be restored // IsDeleted columns were removed in 3.2.2 however SQLite did not support column removal so they had to be restored
if (ActiveDatabase.Name != "Sqlite") if (ActiveDatabase.Name != "Sqlite")
{ {
var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase); var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase);

View File

@@ -16,8 +16,11 @@ namespace Oqtane.Migrations.Tenant
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder, ActiveDatabase); if (ActiveDatabase.Name != "Sqlite")
languageEntityBuilder.DropColumn("Name"); {
var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder, ActiveDatabase);
languageEntityBuilder.DropColumn("Name");
}
} }
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)

View File

@@ -16,7 +16,7 @@ namespace Oqtane.Migrations.Tenant
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
// Name column was removed in 5.2.4 however SQLite does not support column removal so it had to be restored // Name column was removed in 5.2.4 however SQLite did not support column removal so it had to be restored
if (ActiveDatabase.Name != "Sqlite") if (ActiveDatabase.Name != "Sqlite")
{ {
var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder, ActiveDatabase); var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder, ActiveDatabase);

View File

@@ -18,7 +18,10 @@ namespace Oqtane.Migrations.Tenant
{ {
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
siteEntityBuilder.DropIndex("IX_Site"); // TenantId, Name siteEntityBuilder.DropIndex("IX_Site"); // TenantId, Name
siteEntityBuilder.DropColumn("TenantId"); if (ActiveDatabase.Name != "Sqlite")
{
siteEntityBuilder.DropColumn("TenantId");
}
} }
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)

View File

@@ -0,0 +1,60 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Oqtane.Databases.Interfaces;
using Oqtane.Migrations.EntityBuilders;
using Oqtane.Repository;
namespace Oqtane.Migrations.Tenant
{
[DbContext(typeof(TenantDBContext))]
[Migration("Tenant.10.00.02.01")]
public class RemoveDeprecatedColumns : MultiDatabaseMigration
{
public RemoveDeprecatedColumns(IDatabase database) : base(database)
{
}
protected override void Up(MigrationBuilder migrationBuilder)
{
// Oqtane 10.0.2 includes support for column removal in SQLite, so we can now clean up deprecated columns
// Folder columns were deprecated in Oqtane 3.2.2
var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase);
folderEntityBuilder.DropColumn("IsDeleted");
if (ActiveDatabase.Name == "Sqlite")
{
/// the following columns were not added back in 3.2.3 but they still exist in SQLite databases
folderEntityBuilder.DropColumn("DeletedBy");
folderEntityBuilder.DropColumn("DeletedOn");
}
// File columns were deprecated in Oqtane 3.2.2
var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase);
// IsDeleted was added back in 3.2.3 for non-SQLLite databases
fileEntityBuilder.DropColumn("IsDeleted");
if (ActiveDatabase.Name == "Sqlite")
{
/// the following columns were not added back in 3.2.3 but they still exist in SQLite databases
fileEntityBuilder.DropColumn("DeletedBy");
fileEntityBuilder.DropColumn("DeletedOn");
}
// Language columns were deprecated in Oqtane 5.2.4
var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder, ActiveDatabase);
languageEntityBuilder.DropColumn("Name");
// Site columns were deprecated in Oqtane 10.0.1
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
if (ActiveDatabase.Name == "Sqlite")
{
/// the following column was removed for non-SQLite databases in 10.0.1
siteEntityBuilder.DropColumn("TenantId");
}
}
protected override void Down(MigrationBuilder migrationBuilder)
{
// not implemented
}
}
}

View File

@@ -34,7 +34,6 @@ namespace Oqtane.Modules.Admin.Files.Manager
if (folder.ModifiedOn >= lastIndexedOn) if (folder.ModifiedOn >= lastIndexedOn)
{ {
changed = true; changed = true;
removed = folder.IsDeleted.Value;
} }
var files = _fileRepository.GetFiles(folder.FolderId); var files = _fileRepository.GetFiles(folder.FolderId);
@@ -78,7 +77,7 @@ namespace Oqtane.Modules.Admin.Files.Manager
Permissions = $"{EntityNames.Folder}:{folder.FolderId}", Permissions = $"{EntityNames.Folder}:{folder.FolderId}",
ContentModifiedBy = file.ModifiedBy, ContentModifiedBy = file.ModifiedBy,
ContentModifiedOn = file.ModifiedOn, ContentModifiedOn = file.ModifiedOn,
IsDeleted = (removed || file.IsDeleted.Value) IsDeleted = (removed)
}; };
searchContents.Add(searchContent); searchContents.Add(searchContent);
} }

View File

@@ -72,7 +72,6 @@ namespace Oqtane.Repository
public File AddFile(File file) public File AddFile(File file)
{ {
using var db = _dbContextFactory.CreateDbContext(); using var db = _dbContextFactory.CreateDbContext();
file.IsDeleted = false;
db.File.Add(file); db.File.Add(file);
db.SaveChanges(); db.SaveChanges();
file.Folder = _folderRepository.GetFolder(file.FolderId); file.Folder = _folderRepository.GetFolder(file.FolderId);

View File

@@ -51,7 +51,6 @@ namespace Oqtane.Repository
public Folder AddFolder(Folder folder) public Folder AddFolder(Folder folder)
{ {
using var db = _dbContextFactory.CreateDbContext(); using var db = _dbContextFactory.CreateDbContext();
folder.IsDeleted = false;
db.Folder.Add(folder); db.Folder.Add(folder);
db.SaveChanges(); db.SaveChanges();
_permissions.UpdatePermissions(folder.SiteId, EntityNames.Folder, folder.FolderId, folder.PermissionList); _permissions.UpdatePermissions(folder.SiteId, EntityNames.Folder, folder.FolderId, folder.PermissionList);

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using Oqtane.Shared; using Oqtane.Shared;
namespace Oqtane.Models namespace Oqtane.Models
@@ -55,13 +56,6 @@ namespace Oqtane.Models
/// </summary> /// </summary>
public string Description { get; set; } public string Description { get; set; }
/// <summary>
/// Deprecated
/// Note that this property still exists in the database because columns cannot be dropped in SQLite
/// Therefore the property must be retained/mapped even though the framework no longer uses it
/// </summary>
public bool? IsDeleted { get; set; }
/// <summary> /// <summary>
/// Object reference to the <see cref="Folder"/> object. /// Object reference to the <see cref="Folder"/> object.
/// Use this if you need to determine what <see cref="Site"/> the file belongs to. /// Use this if you need to determine what <see cref="Site"/> the file belongs to.
@@ -74,5 +68,16 @@ namespace Oqtane.Models
/// </summary> /// </summary>
[NotMapped] [NotMapped]
public string Url { get; set; } public string Url { get; set; }
#region Deprecated Properties
[Obsolete("The IsDeleted property is deprecated. Soft delete of files is not supported.", false)]
[NotMapped]
[JsonIgnore] // exclude from API payload
public bool? IsDeleted { get; set; }
#endregion
} }
} }

View File

@@ -67,13 +67,6 @@ namespace Oqtane.Models
/// </summary> /// </summary>
public string CacheControl { get; set; } public string CacheControl { get; set; }
/// <summary>
/// Deprecated
/// Note that this property still exists in the database because columns cannot be dropped in SQLite
/// Therefore the property must be retained/mapped even though the framework no longer uses it
/// </summary>
public bool? IsDeleted { get; set; }
/// <summary> /// <summary>
/// TODO: todoc what would this contain? /// TODO: todoc what would this contain?
/// </summary> /// </summary>
@@ -110,6 +103,11 @@ namespace Oqtane.Models
} }
} }
[Obsolete("The IsDeleted property is deprecated. Soft delete of folders is not supported.", false)]
[NotMapped]
[JsonIgnore] // exclude from API payload
public bool? IsDeleted { get; set; }
#endregion #endregion
} }
} }

View File

@@ -31,9 +31,8 @@ namespace Oqtane.Models
/// <summary> /// <summary>
/// Language Name - corresponds to <see cref="Culture.DisplayName"/>, _not_ <see cref="Culture.Name"/> /// Language Name - corresponds to <see cref="Culture.DisplayName"/>, _not_ <see cref="Culture.Name"/>
/// Note that this property still exists in the database because columns cannot be dropped in SQLite
/// Therefore the property must be retained/mapped even though the framework populates it from the Culture API
/// </summary> /// </summary>
[NotMapped]
public string Name { get; set; } public string Name { get; set; }
[NotMapped] [NotMapped]