SubSonic と sqlite を使用して主キー値を挿入する - SubSonic は列が AutoIncrement であるかどうかのいずれかであると考えるための問題

StackOverflow https://stackoverflow.com/questions/2283063

質問

SubSonic 2.2 と sqlite を使用していますが、AUTOINCREMENT ではない INTEGER PRIMARY KEY 列を持つテーブルを処理するときに問題が発生しました。による よくある質問:

テーブルの列を INTEGER PRIMARY KEY として宣言すると、テーブルのその列に NULL を挿入するたびに、NULL はその列の他のすべての行の最大値より 1 大きい整数に自動的に変換されます。テーブル内、またはテーブルが空の場合は 1。

したがって、sqlite はこれらの列を次のように考えます。 時々 自動インクリメントされます (つまり、NULL 値が指定された場合のみ)。問題は、SubSonic が彼らをそう思っていることです。 いつも 自動的に増加します。

私のアプリケーションでは、ID 値はリモート データベースから生成されるため、sqlite で ID 値を自動生成したくありません。これは問題ありません。このテーブルにレコードを作成するときに値を指定するだけです。ただし、SubSonic の sonic.exe を使用して DAL を自動生成すると、主キー列が AutoIncrement = true に設定されます。これは、ID 列を設定できないことを意味しているようです。subsonic の ActiveHelper.GetInsertCommand() は、ID 列が自動生成されると考えているため、それを無視します。

自動インクリメントかどうかを決定する行は、SubSonic.SQLiteDataProvider.GetTableSchema() にあります。

column.AutoIncrement = Convert.ToBoolean(row["PRIMARY_KEY"]) && GetDbType(row["DATA_TYPE"].ToString()) == DbType.Int64;

解決策はどちらかだと思います

  • 他の場所で生成されたキーに INTEGER PRIMARY KEY 列を使用しないでください。

  • この種の列が AutoIncrement = true に設定されないようにテンプレートを変更します。これは、SubSonic がそれらを自動増分として扱わないことを意味するため、後で自動生成された値を取得することを期待しないように注意する必要があります。残念ながら、その列が本当に AUTOINCREMENT であるかどうかをテンプレート内で簡単に判断することはできないと思います。そのため、代わりに醜いハードコーディングを行う必要があるかもしれません。

他にご意見やご提案はありますか?

役に立ちましたか?

解決

残念ながら、それは私たちのSQLiteDataProviderを前提としてのように見える、それがInt64のPK、それの自動インクリメントをだ場合。スキーマを取得するために構築されたSystem.Data.Common.DbConnectionを使用する - 私は今、ソース上で探しています(私はこのプロバイダを書いていない)と私は、スキーマがロードされている方法はConnection.GetSchemaを使用していることがわかりますテーブル用ます。

それは限られた情報を返すため、

これは時間の次善のほとんどです。この場合 - カラムはAUTOINCREMENTであるかどうか、それは私たちに言っていません。そこテーブルの上にSQLiteのメタ情報を依頼するより良い方法は、おそらくです - 。しかし、それは残念ながら使用されませんでした。

短い答え:あなたができる場合は、新しいPKを定義し、参照として他のキーを使用する

他のヒント

私は12月に改訂SQLiteDataProviderにチェックインする前に

として、私が言及しました。 SQLiteDataProvider.cs中線407であなたが持っていることを確認します:

//自動インクリメント検出最近System.Data.SQLiteで利用できるようになりました。 1.0.60.0 - ポール column.AutoIncrement = Convert.ToBoolean(行[ "オートインクリメント"]);

周囲のラインで他のいくつかの改良とバグの修正もあります。新しいコードはgithubの私の推測では、メインプロジェクトの配布に追加されていなかった、私はあまりにも多くのプロジェクトに従っていません。 SQLiteは、ファイルレベルのロックとは別に素晴らしい提供しています。私はSQLiteのの新しい外部キー機能を使用していますSystem.Data.SQLiteのホーム成長したバージョンを持っている、と公式バージョンは

?今月行われるべきです

ここ改訂版は、次のとおりです。 SQLiteDataProvider.csする

ところで、あなたはSQL Serverから変換する必要がある場合には、このプロジェクトをチェックアウトします:

SQLiteのDBにSQL ServerのDBを変換します http://www.codeproject.com/KB/database/convsqlservertosqlite.aspx

私は私が原因ファイルロックのSqlDataProviderのように書かれたのCreateConnectionを使用することはできません見つけます。それが今であるようSQLiteDataProvider中のCreateConnectionは、新しい接続文字列を無視するので、間違っています。

System.Data.SQLiteドキュメントは、あなたが複数のスレッドを作成する可能性がありますし、それらのスレッドがデータベースにアクセスするための独自のSQLiteConnectionとその後のオブジェクトを作成することができます」と言う。同じデータベースファイルへの複数のスレッドで複数の接続が完全に受け入れていると動作します予想通り。 "

それでは、私が試したことは次のようであり、それは本当にcludgeyです。スレッドIDと接続文字列をキーとの接続の辞書を使用してください。しかし、ユニットテストのすべては、トランザクション(より良いテストを必要とする)のほとんどを含め、合格します。私は、クリティカルセクションのロックで、カップルより多くのトランザクションのテストを書いた、と私はより現実的なテストを必要とする、それがスレッドセーフであるかもしれないと考えています。

private Dictionary<string, SQLiteConnection> threadConnectionTable = new Dictionary<string, SQLiteConnection>();

public override DbConnection CreateConnection(string newConnectionString)
{
    SQLiteConnection conn;
    string connKey = "t" + Thread.CurrentThread.ManagedThreadId + "__" + newConnectionString;
    if(threadConnectionTable.ContainsKey(connKey))
    {
        conn = threadConnectionTable[connKey];
        if(conn.State != ConnectionState.Open)
            conn.Open();
        return conn;
    }
    conn = new SQLiteConnection(newConnectionString);
    conn.Open();
    threadConnectionTable[connKey] = conn;
    return conn;
}



private Object thisLock = new Object();

[Test]
[ThreadedRepeat(10)]
public void MultiThreadRepeat()
{
    lock(thisLock)
    {
        var qcc = new QueryCommandCollection();
        int threadId = Thread.CurrentThread.ManagedThreadId;
        Debug.WriteLine("MultiThreadRepeat: thread id = " + threadId);
        int count = 0;
        for(int n = 0; n < 10; n++)
        {
            Query qry1 = new Query(Product.Schema);
            qry1.QueryType = QueryType.Update;
            qry1.AddWhere(Product.Columns.ProductID, n);
            qry1.AddUpdateSetting("ProductName", threadId + ": unit test ");
            QueryCommand cmd = qry1.BuildUpdateCommand();
            qcc.Add(cmd);
            count++;
        }
        DataService.ExecuteTransaction(qcc);
        var p1 = new Product(1);
        Assert.AreEqual(p1.ProductName, threadId + ": unit test ", StringComparison.InvariantCultureIgnoreCase);
    }

}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top