c# - SQLite错误:不存在这样的表main.table_name

标签 c# sqlite uwp

在我的UWP应用中,我正在sqlite数据库中的“应用开始”上创建表。另外,我编写了各种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(); 
 } 
}

最佳答案

发生了什么

由于在版本3.25.0(2018-09-15)和3.26.0(2018-12-01)中对SQLite的ALTER TABLE命令进行了更改,因此出现了您的问题。有关官方文档,请参见SQLite网站上的ALTER TABLE

在此版本之前,重命名表(例如,从MY_TABLEA_BETTER_NAMED_TABLE)只能更改表的名称。对该表的任何引用(即在外键(FK)约束或触发器中)均未重命名。如果目标是仅重命名表,则可以合理地将其视为错误,因为没有(简便,正式)的方式来更改这些引用,并且您将获得不一致的数据库。

上面的更改通过将对表名的更改传播到任何此类引用中来“解决”了此问题。因此,您可以重命名由FK约束或触发器引用的表,并保留一个一致的数据库。

何时引起问题

由于ALTER TABLE命令的能力非常有限(与非Lite数据库引擎相比),OP的问题间接地出现了。在SQLite中,它所能做的就是更改表名,列名或添加新列(到行的“结尾”)。如果您需要对表执行比该表更复杂的操作,则必须进行“创新”(本质上是,创建一个新的替换表并从旧表中填充它)。但是,有两种方法可以做到这一点,其中一种被上述更改“试图变得更有用”而“中断”。

安全的方法


使用所需的所有新属性创建一个新的(例如MY_TABLE_NEW)。
将现有数据从MY_TABLE迁移到MY_TABLE_NEW(适当添加默认值/缺失值)。
删除原始表MY_TABLE。此时,任何引用MY_TABLE的FK约束和触发器都将失败,但这无关紧要。
使用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的引用)。

修复

可以将表操作步骤的顺序更改为“安全方式”中的顺序,也可以按照ALTER TABLE页上的说明,在PRAGMA legacy_alter_table=ON命令之前发出命令ALTER TABLE。这将防止“改进”行为将对MY_TABLE的引用重命名为MY_TABLE_OLD

关于c# - SQLite错误:不存在这样的表main.table_name,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57253045/

相关文章:

c# - 通用列表 - 在列表中移动一个项目

c# - 不允许循环文件引用。发布 ASP.NET (2.0) 网站

ios - 数据库执行查询错误 : SQL logic error or missing database xcode

c# - uwp 应用程序(.net native )和未处理的异常

c# - 如何在 C# 中本地化密码验证?

Android Room,SQLite - 出乎意料,得到了 'COLUMN'

android - 如何将缓存数据保存到sqlite DB(android)

mvvm - UWP 绑定(bind)到 MVVM 中的 AutoSuggestBox

c# - UWP InkCanvas 用颜色填充徒手绘制的形状

c# - WSE + 自签名证书