2011-07-01 18 views
0

c#/linqでデータベースにクエリするのにSystem.Data.SQLiteを使用しています。 表示する行には、さまざまなテーブルのデータが含まれています。私が現在行っていることは、DataGridに配置するアイテムの完全なリストを取得するために1つのテーブルを照会することです。仮想化のおかげで、関連する行が表示されるので、他のテーブルを遅延クエリすることができます。これは正常に動作します。System.Data.SQLite非同期ロードの問題

今、行の欠落しているデータをただちに非同期で入力したいと考えています。しかし、「DataReaderが終了しました」という例外が発生します。たびに、別のスレッドで遅延読み込みコードを実行します。これは、 "元の" linqクエリが別のスレッドから行われたという事実と関係していますか?

どのように私はこれを修正できますか?ここで

がうまくいけば、遅延ロード・ループは同じ問題が表示されない_mainLoadEventを上げる

//Main thread--- 

//Start the search 
_startEvent.Set(); 
_mainLoadEvent.WaitOne(); 
_mainLoadEvent.Reset(); 


//Worker thread--- 

_startEvent.WaitOne(); 
_startEvent.Reset(); 

SearchAllLiterature(); //Fills _searchResults with rows 

_mainLoadEvent.Set(); //Signal to mainthread that all rows are loaded 

//Fill in some details for every row, that come from various sources, we'll need them later 
foreach (var r in _searchResults) 
    r.LazyLoadText(); 


//SearchResultRow.cs 

public string Author 
{ 
    get 
    { 
     LazyLoadText(); 
     return _author; 
    } 

    set 
    { 
     _author = value; 
    } 
} 


//Called by the worker thread or by the DataGrid when a new row comes into view 
public void LazyLoadText() 
{ 
    lock (this) 
    { 
     if (_lazyLoadTextCompleted) return; 

     _lazyLoadTextCompleted = true; 
    } 

    var sb = new StringBuilder(); 

    //this will result in a SQL-query 
    var authors = from a in _source.ReferenceOrganization 
       orderby a.Person.LastName 
       select a.Person; 

    Author = ConcatAuthors(authors, sb); 

    //...more queries... 
} 

後に問題をまとめていくつかのコードです。

LazyLoadメソッドのコード全体に静的ロックを設定すると、この問題も解決されます。同時にクエリを開始するのは問題ないようですが、これは本当ですか?

+2

関連するコードを投稿してください... –

+0

私のポストにいくつかのコードを追加しました。面白いことに、レイジーローディングを開始する前に、ワーカースレッドが約1秒間スリープすると、問題はなくなります。私は、これは、表示する必要がある行の怠惰な読み込みを完了するのに十分な時間UIを与えると思います。しかし、なぜこれが問題なのでしょうか?ロック機構が間違っていますか? –

答えて

2

SQLiteのデータコンテキストはスレッドセーフではないことがわかりました。 linq-queriesが暗黙のうちに同じコンテキストを使用していると、私は問題に遭遇しました。いくつかのコンテキストを使用すると問題は解消されますが、残念ながらコンテキストには別々のキャッシュがあります(またはそう思われます)ので、1つのスレッドをバックグラウンドでロードすると別のスレッドで後で検索する利点がありません。基本的に全体のアイデアでした。 メインスレッドで現在データベースにアクセスしていない場合でも、バックグラウンドでロードすることは有効です。私はそれを決定するエレガントな方法を本当に考え出していませんが。

+0

スレッドごとの別のキャッシュはもはや問題ではなく、しばらくありませんでした。また、3.7.0で導入されたWrite Ahead Loggingの一部では、マルチスレッド、特にマルチプロセスのパフォーマンスが向上しました。 –

+0

バックグラウンドの読み込みを処理するための私の提案は、読み込みに1つのスレッドのみを使用することです。メインスレッドがバックグラウンドスレッドをトリガーして、すぐに最初のレコードのロードを開始し、ロードされたらデータ(データリーダーではなく、データオブジェクト、つまり値オブジェクトまたはデータテーブル)をメインスレッドに戻します。バックグラウンドスレッドはバックグラウンドでロードを続けることができます。つまり、私の経験では、バックグラウンドの読み込みが必要ないsqliteのパフォーマンスで十分です。たぶんあなたのページサイズとキャッシュサイズを増やすべきでしょう。 –

+0

どのようにして別のキャッシュが問題にならないのですか?私はsearchspeedの違いを測定することができます。私は1つのスレッドからのみロードしています。しかし、まだ表示されていない各行で遅延ロードを使用します。しかし、私はバックグラウンドとUI(まだ話す他のスレッド)で読み込んでいて、プロパティにアクセスすることによっても遅延ロードを要求していました。問題が起きた場所 –

-2

ok読者が閉じる前にThread.Sleep()を試してください; あなたの2番目のスレッドは時間がかかりますか?働く? あなたはその後、メインスレッドを完了(スレッド2が完了した)場合のような何かをするかもしれません...他に待つ; P

私はprollyビットXDを台無しに...

私はこれがあなたの問題であるかどうかわからないんだけど...これは助けにならない場合は申し訳ありません...私は5ヶ月好きです プログラミング経験:P

+0

私は読者を閉じている人ではありません。そうでなければ、2番目のスレッドが作業を完了するまで待機します。私は別の問題にぶつかっていると思う。それとも別のことを意味しましたか? –