使用Mono中的LINQ插入Sqlite数据库会引发TargetInvocationException和SqliteException

时间:2014-04-17 05:18:49

标签: c# linq sqlite linq-to-sql mono

我正在尝试打开一个Sqlite文件,并在Mono的表中插入一行。我引用了Mono.Data.SqliteSystem.DataSystem.Data.Linq程序集。 Sqlite文件和表都存在。 Status类具有TableColumn属性。当我单独使用Mono的Sqlite库时,我可以成功插入。

Status data = GetStatusFoo();
using (SqliteConnection con = new SqliteConnection("Data Source=" + Config.SQLITE_DB_FILE + ";Version=3;"))
{
    con.Open();

    using (SqliteCommand cmd = new SqliteCommand("INSERT INTO " + _table + _insert + " VALUES " + _values, con))
    {
        cmd.Parameters.Add(new SqliteParameter("@Timestamp", data.Timestamp));
        // ...
        cmd.ExecuteNonQuery();
    }
    con.Close()
}

但是,我不想输出1000个SqliteParameters,所以我正在尝试使用Linq-to-SQL。以下代码在DataContext构造函数中抛出TargetInvocationException。

Status data = GetStatusFoo();
using (DataContext db = new DataContext("Data Source=" + Config.SQLITE_DB_FILE + ";Version=3;"))
{
    Table<Status> statuses = db.GetTable<Status>();
    statuses.InsertOnSubmit(data);
    db.SubmitChanges();
}

它抱怨Version不是有效的关键字,所以当我删除它时,只留下

Status data = GetStatusFoo();
using (DataContext db = new DataContext("Data Source=" + Config.SQLITE_DB_FILE + ";")
{
    Table<Status> statuses = db.GetTable<Status>();
    statuses.InsertOnSubmit(data);
    db.SubmitChanges();
}

它在db.SubmitChanges()抛出一个System.Data.SqlClient.SqlException,表示“服务器不存在或连接被拒绝”。

但是,当我使用SqliteConnection进行DataContext的IDbConnection时,这会发生变化,即

Status data = GetStatusFoo();
using (SqliteConnection con = new SqliteConnection("Data Source=" + Config.SQLITE_DB_FILE + ";"))
using (DataContext db = new DataContext(con))
{
    Table<Status> statuses = db.GetTable<Status>();
    statuses.InsertOnSubmit(data);
    db.SubmitChanges();
}

这会在SQLite error unrecognized token: "@"处抛出Mono.Data.Sqlite.SqliteException:db.SubmitChanges();

添加Version=3;没有帮助,尝试Version=2会抛出System.NotSupportedException。 Console和DataContext.Log给出如下内容:

INSERT INTO [Status] ([Timestamp], ...) VALUES (@Timestamp, ...)
-- @Timestamp: Input Int64 (Size = 0; Prec = 0; Scale = 0) [1397710927]
-- ...
-- Context: SqlServer Model: AttributedMetaModel Build: 4.0.0.0
SELECT @@IDENTITY
-- @Timestamp: Input Int64 (Size = 0; Prec = 0; Scale = 0) [1397710927]
-- Context: SqlServer Model: AttributedMetaModel Build: 4.0.0.0

Unhandled Exception:
Mono.Data.Sqlite.SqliteException: SQLite error
unrecognized token: "@"

是什么给出的?为什么它不喜欢“@”符号?是否未能进行参数替换?或者最后是@@IDENTITY来电?

编辑:其他信息

在堆栈跟踪之后,在Mono.Data.SqliteCommand.BuildNextCommand和this.CommandText == "SELECT @@IDENTITY"中发生SqliteException异常。显然,SQLite不支持此MS / Transact-SQL命令。据我所知,在DbLinq.Data.Linq.Sugar.Implementation.QueryRunner.Upsert (target={Status}, insertQuery={DbLinq.Data.Linq.Sugar.UpsertQuery})

中创建了一个“outputCommand”

所以我正在改变我的问题包括:我如何告诉Linq避免仅使用SQL的命令?

1 个答案:

答案 0 :(得分:1)

我对我的问题有部分答案。

DbLinqProvider=sqlite;添加到SqliteConnection查询字符串会告诉Linq-to-SQL使用SQLite命令,并修复"SELECT @@IDENTITY"问题。此代码有效:

Status data = GetStatusFoo();
using (SqliteConnection con = new SqliteConnection("Data Source=" + Config.SQLITE_DB_FILE + ";DbLinqProvider=sqlite;"))
using (DataContext db = new DataContext(con))
{
    Table<Status> statuses = db.GetTable<Status>();
    statuses.InsertOnSubmit(data);
    db.SubmitChanges();
}

但是,我仍然需要使用SqliteConnection对象,因为new DataContext("Data Source=" + Config.SQLITE_DB_FILE + ";DbLinqProvider=sqlite;")仍然会抛出&#34;服务器不存在或连接被拒绝&#34;异常。

编辑:完整答案

事实证明,如果没有DbLinqConnectionType参数,DataContext默认使用System.Data.SqlClient.SqlConnection进行连接。连接类型必须是程序集完全限定名称,因此以下代码适用于我:

// in Config
public static string SQLITE_CONNECTION_CLASS_AQN = typeof(Mono.Data.Sqlite.SqliteConnection).AssemblyQualifiedName


// in database class
static string _connection_string = "Data Source=" + Config.SQLITE_DB_FILE + ";DbLinqProvider=sqlite;DbLinqConnectionType=" + Config.SQLITE_CONNECTION_CLASS_AQN + ";";


// in database method
Status data = GetStatusFoo();
using (DataContext db = new DataContext(_connection_string))
{
    Table<Status> statuses = db.GetTable<Status>();
    statuses.InsertOnSubmit(data);
    db.SubmitChanges();
}

供参考,typeof(Mono.Data.Sqlite.SqliteConnection).AssemblyQualifiedName评估为"Mono.Data.Sqlite.SqliteConnection, Mono.Data.Sqlite, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756"