简体   繁体   English

使用System.Data.Linq.Mapping并在sqlite db中自动递增主键时出错

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

I'm using SQLite and System.Data.Linq.Mapping . 我正在使用SQLiteSystem.Data.Linq.Mapping I'm having an issue with the id AUTOINCREMENT field when using the linq mapping attribute IsDbGenerated = true . 当使用linq映射属性IsDbGenerated = true时,我遇到了id AUTOINCREMENT字段的问题。

Syntax to create my table. 创建表的语法。 I've tried this with/without the AUTOINCREMENT 我用/不用AUTOINCREMENT试过这个

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

My TABLE class: 我的TABLE类:

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

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

Here's how I call it. 这是我如何称呼它。 When it goes to submit I get a error, I'll paste the error below this example. 当它提交我得到一个错误,我将粘贴此示例下面的错误。 One thing to note is if I take out the IsDbGenerated =true above and enter the id manually it does insert fine, but I'd like it to AUTOINCREMENT and for some reason the IsDbGenerated=true is killing the insert. 有一点需要注意的是,如果我取出上面的IsDbGenerated =true并手动输入id ,它确实插入正常,但我想它为AUTOINCREMENT ,由于某种原因, IsDbGenerated=true正在杀死插入。 Looking for some guidance. 寻求一些指导。

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();
}

Error message: 错误信息:

SQL logic error or missing database\\r\\nnear \\"SELECT\\": syntax error SQL逻辑错误或缺少数据库\\ r \\ nnene \\“SELECT \\”:语法错误

Stack trace: 堆栈跟踪:

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 在System.Data.SQLite.SQLite3.Prepare(SQLiteConnection cnn,String strSql,SQLiteStatement previous,UInt32 timeoutMS,String&strRemain)\\ r \\ n在System.Data.SQLite.SQLiteCommand.BuildNextCommand()\\ r \\ n在System.Data在System.Data.SQLite.SQLiteDataReader..ctor的System.Data.SQLite.SQLiteDataReader.NextResult()\\ r \\ n中的.SQLite.SQLiteCommand.GetStatement(Int32 index)\\ r \\ n(SQLiteCommand cmd,CommandBehavior behave)\\ r \\ n \\ n位于System.Data.Comite.DbCommand.ExecuteReader()的System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)\\ r \\ n,位于System.Data.SQLite.SQLiteCommand.ExecuteDbDataReader(CommandBehavior behavior)\\ r \\ n \\ 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" 在System.Data.Linq.SqlClient.SqlProvider.Execute(表达式查询,QueryInfo queryInfo,IObjectReaderFactory工厂,Object [] parentArgs,Object [] userArgs,ICompiledSubQuery [] subQueries,Object lastResult)\\ r \\ n在System.Data.Linq .SqlClient.SqlProvider.ExecuteAll(Expression query,QueryInfo [] queryInfos,IObjectReaderFactory factory,Object [] userArguments,ICompiledSubQuery [] subQueries)\\ r \\ n在System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider .IProvider.Execute(表达式查询)\\ r \\ n在System.Data.Linq.ChangeDirector.StandardChangeDirector.DynamicInsert(TrackedObject item)\\ r \\ n在System.Data.Linq.ChangeDirector.StandardChangeDirector.Insert(TrackedObject item)\\ r \\ n \\ n at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)\\ r \\ n在System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)\\ r \\ n在System.Data.Linq.DataContext.SubmitChanges() \\ r \\ n在Program.cs中的SqlLinq.Program.Main(String [] args):第29行“

Here is what I'm seeing in the log output: 这是我在日志输出中看到的内容:

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

According to the SQLite documentation ( A column declared INTEGER PRIMARY KEY will AUTOINCREMENT. ) just remove AUTOINCREMENT in your Table creation, Writing integer primary key is enough. 根据SQLite文档( 一行声明INTEGER PRIMARY KEY将AUTOINCREMENT。 )只需删除表创建中的AUTOINCREMENT ,写入integer primary key就足够了。 SQLite will automatically increment your ids : SQLite会自动增加你的ids

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

Also you don't need to set IsDbGenerated = true in your TestTable class and don't enter the id manually, it does insert fine just by inserting title : 此外,您不需要在TestTable类中设置IsDbGenerated = true ,也不需要手动输入id ,只需插入title即可插入:

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

Edit: Your TestTable should look like this now: 编辑:您的TestTable现在应该如下所示:

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

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

The result in SQLite Manager: SQLite管理器中的结果:

结果

How do I create an AUTOINCREMENT field 如何创建AUTOINCREMENT字段

Short answer : A column declared INTEGER PRIMARY KEY will autoincrement. 简答 :声明为INTEGER PRIMARY KEY的列将自动递增。

Longer answer: If you declare a column of a table to be INTEGER PRIMARY KEY, then whenever you insert a NULL into that column of the table, the NULL is automatically converted into an integer which is one greater than the largest value of that column over all other rows in the table, or 1 if the table is empty. 更长的答案:如果将一个表的列声明为INTEGER PRIMARY KEY,那么无论何时在表的该列中插入NULL,NULL都会自动转换为一个整数,该整数大于该列的最大值。表中的所有其他行,如果表为空,则为1。 Or, if the largest existing integer key 9223372036854775807 is in use then an unused key value is chosen at random. 或者,如果正在使用最大的现有整数密钥9223372036854775807,则随机选择未使用的密钥值。 For example, suppose you have a table like this: 例如,假设您有一个这样的表:

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

With this table, the statement 有了这个表,声明

INSERT INTO t1 VALUES(NULL,123);

is logically equivalent to saying: 在逻辑上等同于说:

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

There is a function named sqlite3_last_insert_rowid() which will return the integer key for the most recent insert operation. 有一个名为sqlite3_last_insert_rowid()的函数,它将返回最近插入操作的整数键。

Note that the integer key is one greater than the largest key that was in the table just prior to the insert. 请注意,整数键比插入前表中的最大键大1。 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. 要创建在表的生命周期内唯一的键,请将AUTOINCREMENT关键字添加到INTEGER PRIMARY KEY声明中。 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. 如果该表中先前存在最大可能键,则INSERT将失败并显示SQLITE_FULL错误代码。

References : 参考文献:

Autoincrement in SQLite SQLite中的自动增量

How to create Autoincrement Field ? 如何创建自动增量字段?

SO post dealing with Autoincrement in SQLite 所以在SQLite中处理Autoincrement

SQLLite doesn't work with Linq commands for autoincrement values This command produces error SQLLite不能与Linq命令一起使用自动增量值此命令会产生错误

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

You have only 2 way: 你只有两种方式:

  1. Do not use Linq for SQLLite. 不要将Linq用于SQLLite。 Use some third party solutions, or your own commands. 使用某些第三方解决方案或您自己的命令。

  2. Use another ways to inrement your ID, as it was written by [utility] 使用其他方式来修改您的ID,因为它是由[实用程序]编写的

The first one better, because there are other examples of SQL statements being passed to sqlite via Linq which aren't valid. 第一个更好,因为有其他SQL语句的例子通过Linq传递给sqlite是无效的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM