2017-03-29 52 views
0

我試圖用ReactiveX(更確切地說,Rx.Net)和SQLite.Net構建一個數據訪問層。ReactiveX:使Observable.Create()只被調用一次

工作的一部分是創建一個可觀察的數據庫連接,以便只在需要時纔可以打開它。這是我到目前爲止:

var connection = Observable.Create<SQLiteConnection>(observer => 
{ 
    Debug.WriteLine("CheckInStore: Opening database connection"); 
    var database = new SQLiteConnection(configuration.ConnectionString.DatabasePath); 

    observer.OnNext(database); 
    observer.OnCompleted(); 

    return Disposable.Create(() => 
    { 
     Debug.WriteLine("CheckInStore: Closing database connection"); 
     database.Close(); 
    }); 
}); 


// Further down the line, a query would look like this: 
var objects = connection.SelectMany(db => db.Query<>("select * from MyTable")); 

不幸的是,每當有人訂閱這個可觀察的,一個新的連接被創建。一旦訂閱被處置,它也會關閉。

我試過使用.Replay(1).RefCount(),但它沒有改變任何東西。無論如何,我不確定要了解整個RefCount的事情。

我該如何使這個數據庫連接成爲單例?

回答

0

看一看這個代碼,這是等價的,但不會打開一個數據庫連接:

var conn = Observable.Create<int>(o => 
    { 
     Debug.WriteLine("Opening"); 
     o.OnNext(1); 
     o.OnCompleted(); //This forces closing code to be called. Comment me out. 
     return Disposable.Create(() => 
     { 
      Debug.WriteLine("Closing"); 
     }); 
    }) 
    //.Replay(1) 
    //.RefCount() //.Replay(1).RefCount is necessary if you want to cache the result 
    ; 

var sub1 = conn.SelectMany(i => Observable.Return(i)).Subscribe(i => Debug.WriteLine($"1: {i}")); 
var sub2 = conn.SelectMany(i => Observable.Return(i)).Subscribe(i => Debug.WriteLine($"2: {i}")); 
sub1.Dispose(); 
sub2.Dispose(); 
var sub3 = conn.SelectMany(i => Observable.Return(i)).Subscribe(i => Debug.WriteLine($"3: {i}")); 
sub3.Dispose(); 

有一些問題在這裏:

  1. 你的物/退訂代碼每次你退訂或者完成觀察時都會被調用。由於您要求OnCompleted,因此每次都會打開/關閉。
  2. 如果要重新使用相同的連接,則需要使用.Replay(1).RefCount()。每次用戶連接時,Observable.Create都會運行整個功能,除此之外沒有任何東西(除了.Replay(1).Refcount())爲您緩存。
  3. 即使您添加了.Replay(1).Refcount()並刪除了OnCompleted,但如果沒有未完成的訂閱(例如在sub2.Dispose()調用之後),仍然會得到處置(意味着數據庫關閉)行爲。
  4. 如果您不通過using(var sub = connection.SelectMany(...))或明確通過sub.Dispose()來處置訂閱,那麼您將永遠不會取消訂閱,因爲此Observable無法終止訂閱。換句話說,相反的問題3,你的代碼將永遠不會發生。

我希望你得到的圖片:這是一個很容易出錯的做事方式。我會推薦一個簡單的迭代調用,因爲無論如何,這往往會更好地用於DB調用。如果你堅持RX,我會考慮Observable.Using爲你的數據庫連接初始化。