使用 System.Data.Linq.Mapping 并自动递增 sqlite 数据库中的主键时出错

Error using System.Data.Linq.Mapping and auto incrementing the primary key in a sqlite db

我正在使用 SQLiteSystem.Data.Linq.Mapping。使用 linq 映射属性 IsDbGenerated = true.

时,id AUTOINCREMENT 字段出现问题

创建我的 table 的语法。我试过这个 with/without AUTOINCREMENT

CREATE TABLE [TestTable] ([id] INTEGER  NOT NULL PRIMARY KEY AUTOINCREMENT,[title] TEXT  NULL)

我的TABLEclass:

[Table(Name = "TestTable")]
public class TestTable
{
    [Column(IsPrimaryKey = true, IsDbGenerated =true)]
    public int id { get; set; }

    [Column]
    public string title { get; set; }
}

我是这样称呼它的。提交时出现错误,我会将错误粘贴到此示例下方。需要注意的一件事是,如果我取出上面的 IsDbGenerated =true 并手动输入 id 它确实可以正常插入,但我希望它插入 AUTOINCREMENT 并且出于某种原因 IsDbGenerated=true 正在终止插入。寻求指导。

static void Main(string[] args)
{
    string connectionString = @"DbLinqProvider=Sqlite;Data Source = c:\pathToDB\test.s3db";
    SQLiteConnection connection = new SQLiteConnection(connectionString);
    DataContext db = new DataContext(connection);
    db.Log = new System.IO.StreamWriter(@"c:\pathToDB\mylog.log") { AutoFlush = true };

    var com = db.GetTable<TestTable>();
    com.InsertOnSubmit(new TestTable {title = "asdf2" });
    try {
        db.SubmitChanges();
    }
    catch(SQLiteException e)
    {
        Console.WriteLine(e.Data.ToString());
        Console.WriteLine(e.ErrorCode);
        Console.WriteLine(e.HelpLink);
        Console.WriteLine(e.InnerException);
        Console.WriteLine(e.Message);
        Console.WriteLine(e.StackTrace);
        Console.WriteLine(e.TargetSite);
        Console.WriteLine(e.ToString());
    }
    foreach (var TestTable in com)
    {
        Console.WriteLine("TestTable: {0} {1}", TestTable.id, TestTable.title);
    }
    Console.ReadKey();
}

错误信息:

SQL logic error or missing database\r\nnear \"SELECT\": syntax error

堆栈跟踪:

at System.Data.SQLite.SQLite3.Prepare(SQLiteConnection cnn, String strSql, SQLiteStatement previous, UInt32 timeoutMS, String& strRemain)\r\n at System.Data.SQLite.SQLiteCommand.BuildNextCommand()\r\n at System.Data.SQLite.SQLiteCommand.GetStatement(Int32 index)\r\n at System.Data.SQLite.SQLiteDataReader.NextResult()\r\n at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)\r\n at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)\r\n at System.Data.SQLite.SQLiteCommand.ExecuteDbDataReader(CommandBehavior behavior)\r\n at System.Data.Common.DbCommand.ExecuteReader()\r\n
at System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, Object lastResult)\r\n at System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries)\r\n at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)\r\n at System.Data.Linq.ChangeDirector.StandardChangeDirector.DynamicInsert(TrackedObject item)\r\n at System.Data.Linq.ChangeDirector.StandardChangeDirector.Insert(TrackedObject item)\r\n at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)\r\n at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)\r\n at System.Data.Linq.DataContext.SubmitChanges()\r\n at SqlLinq.Program.Main(String[] args) in Program.cs:line 29"

这是我在日志输出中看到的内容:

INSERT INTO [company]([title])
VALUES (@p0)

SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value]
-- @p0: Input String (Size = 4000; Prec = 0; Scale = 0) [asdf2]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.6.81.0

SELECT [t0].[id], [t0].[title]
FROM [company] AS [t0]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.6.81.0

How do I create an AUTOINCREMENT field

简答:声明为 INTEGER PRIMARY KEY 的列将自动递增。

更长的答案: 如果您将 table 的列声明为 INTEGER PRIMARY KEY,那么每当您将 NULL 插入 [=51] 的该列时=],NULL 会自动转换为整数,该整数比 table 中该列的最大值大 1,如果 table 为空,则为 1。或者,如果最大的现有整数键 9223372036854775807 正在使用中,则随机选择一个未使用的键值。例如,假设您有一个像这样的 table:

CREATE TABLE t1(
  a INTEGER PRIMARY KEY,
  b INTEGER
);

有了这个table,声明

INSERT INTO t1 VALUES(NULL,123);

在逻辑上等同于说:

INSERT INTO t1 VALUES((SELECT max(a) FROM t1)+1,123);

有一个名为 sqlite3_last_insert_rowid() 的函数,它将 return 最近插入操作的整数键。

Note that the integer key is one greater than the largest key that was in the table just prior to the insert. The new key will be unique over all keys currently in the table, but it might overlap with keys that have been previously deleted from the table. To create keys that are unique over the lifetime of the table, add the AUTOINCREMENT keyword to the INTEGER PRIMARY KEY declaration. Then the key chosen will be one more than the largest key that has ever existed in that table. If the largest possible key has previously existed in that table, then the INSERT will fail with an SQLITE_FULL error code.

参考资料:

Autoincrement in SQLite

How to create Autoincrement Field ?

SO post dealing with Autoincrement in SQLite

根据 SQLite 文档 (A column declared INTEGER PRIMARY KEY will AUTOINCREMENT.),只需删除 Table 创建中的 AUTOINCREMENT,写 integer primary key 就足够了。 SQLite 会自动增加你的 ids:

sqlite_cmd.CommandText = "CREATE TABLE [TestTable] ([id] INTEGER PRIMARY KEY NOT NULL , [title] TEXT)";

此外,您不需要在 TestTable class 中设置 IsDbGenerated = true,也不需要手动输入 id,只需插入即可正常插入title:

com.InsertOnSubmit(new TestTable { title = "asdf2" });//will automatically increment id.

编辑: 你的 TestTable 现在应该是这样的:

[Table(Name = "TestTable")]
public class TestTable
{
    [Column(IsPrimaryKey = true)]
    public int? id { get; set; }

    [Column]
    public string title { get; set; }
}

SQLite Manager 中的结果:

SQLLite 不适用于自动增量值的 Linq 命令 此命令产生错误

SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value]

你只有两种方式:

  1. 不要将 Linq 用于 SQLLite。使用一些第三方解决方案,或者您的 自己的命令。

  2. 使用其他方法来增加您的 ID,因为它是由 [utility]

  3. 编写的

第一个更好,因为还有其他 SQL 语句通过 Linq 传递给 sqlite 的例子是无效的。