在我的 UWP 应用中,我在 sqlite db 中的 App Start 上创建表。此外,我编写了各种 Alter 命令,其中我检查已安装的应用程序是否包含 Customertbl 中的相应列,并将 Customertbl 表重命名为 Customertbl_old 并创建新表 Customertbl,最后将 Customertbl_old 表中的所有行存储到 Customertbl 表中。然后我删除表 Customertbl_old。现在,到这部分一切正常,但是,当我尝试在 OwnerTbl 中删除/插入一行时,它会抛出一个异常说
Sqlite 错误:没有这样的表 main.Customertbl_old 存在。
//**Code where a column name is updated by creating new table**
string tableCommand = "PRAGMA table_info(Recordings)";
SqliteCommand createTable = new SqliteCommand(tableCommand, db);
SqliteDataReader query = createTable.ExecuteReader();
tableCommand = "PRAGMA foreign_keys = off; " + "
BEGIN TRANSACTION; " +
" ALTER TABLE Customertbl RENAME TO _Customertbl_old; " +
" CREATE TABLE Customertbl ( " + " ID INTEGER PRIMARY KEY AUTOINCREMENT, " + " CustomerName NVARCHAR(100) NULL, " + " Password NVARCHAR(100) NULL, " + "
pkID INTEGER NULL, " + " ActivityName NVARCHAR(255) NULL);" +
" INSERT INTO Customertbl(Name,Password) " + " SELECT Name,Password " + "
FROM _Customertbl_old ;" + " COMMIT; " + " PRAGMA foreign_keys=on; " + "
DROP TABLE
_Customertbl_old";
// **code where exception occur**
using (SqliteConnection db = new
SqliteConnection("Filename=" + App.dbName))
{
db.Open();
SqliteCommand deleteCommand = new SqliteCommand();
try
{
deleteCommand.Connection = db;
deleteCommand.CommandText = "DELETE FROM Ownertbl where fkId = @id";
deleteCommand.Parameters.AddWithValue("@id", id);
deleteCommand.ExecuteReader()//here the exception occur ;
db.Close();
}
}
Run Code Online (Sandbox Code Playgroud)
如果ALTER TABLE...由于将 SQLite 升级到版本 3.26 或更高版本而导致以前工作的 使用中断,则PRAGMA legacy_alter_table=ON在进行这些更改之前使用“快速修复” 。但是,重新组织命令可能会更好(请参阅“安全方法”)。如果您使用 3.26 后版本的 SQLite 开始一个新项目,我绝对会建议您使用“安全方式”并避免使用PRAGMA.
由于ALTER TABLE在3.25.0 (2018-09-15) 和3.26.0 (2018-12-01)版本中对 SQLite 的命令进行了更改,因此出现了您的问题。有关官方文档,请参阅SQLite 网站上的ALTER TABLE。
在此之前的版本,(例如来自重命名表MY_TABLE到A_BETTER_NAMED_TABLE)只改变了表的名称。对该表的任何引用(即在外键 (FK) 约束或触发器中)都没有重命名。如果目标只是重命名表,这可以合理地被视为一个错误,因为没有(简单的、正式的)方法来更改这些引用,并且会留下不一致的数据库。
上述更改通过将对表名称的更改传播到任何此类引用中来“修复”此问题。因此,您可以重命名 FK 约束或触发器引用的表,并保留一致的数据库。
OP 的问题出现 - 间接 - 由于命令的能力非常有限(与非 Lite 数据库引擎相比)ALTER TABLE。在 SQLite 中,它所能做的就是更改表名、列名或添加新列(到行的“结尾”)。如果您需要对表做任何比这更复杂的事情,您必须“有创意”(本质上,创建一个新的替换表并从旧表中填充它)。但是,有两种方法可以做到这一点,其中一种方法被上述更改“试图变得更有帮助” “打破”。
MY_TABLE_NEW使用您需要的所有新属性创建一个新的(例如)。
将现有数据从 迁移MY_TABLE到MY_TABLE_NEW(根据需要添加默认值/缺失值)。
删除原表MY_TABLE。此时,引用的任何 FK 约束和触发器MY_TABLE都将失败,但这并不重要。
用于ALTER TABLE MY_TABLE_NEW RENAME TO MY_TABLE将格式正确的新表的名称更改回原始表的名称。现在将再次满足任何 FK 约束/触发器引用(假设它们不是针对已删除的列!)
以上将在更改前后都有效。在更改之前,不注意 FK 约束/触发器;更改后,将没有引用,MY_TABLE_NEW因此不会传播任何内容。
在更改之前,以下过程同样有效:
使用ALTER TABLE MY_TABLE RENAME TO MY_TABLE_OLD. 此时,在旧版本中,任何 FK 约束/触发器都会不一致,但这并不重要。
使用您需要的所有新属性创建一个替换表MY_TABLE。现在将满足任何参考。
将现有数据从 迁移MY_TABLE_OLD到MY_TABLE(根据需要添加默认值/缺失值)。
删除原始(但重命名)表MY_TABLE_OLD。
新版本会出现问题,因为它将重命名对原始表 ( MY_TABLE) 的所有引用,以便它们现在引用即将删除的表 ( MY_TABLE_OLD)。其他任何步骤都不会影响这些引用,因此您会得到一个不一致的数据库(对不存在的 的引用MY_TABLE_OLD)。
将表操作步骤的顺序更改为The Safe Way 中的顺序,或者 - 如ALTER TABLE页面上所述- 在命令PRAGMA legacy_alter_table=ON之前发出ALTER TABLE命令。这将防止“改进”行为将引用重命名MY_TABLE为MY_TABLE_OLD.
| 归档时间: |
|
| 查看次数: |
2025 次 |
| 最近记录: |