ReactiveX:只调用一次Observable.Create()

时间:2017-03-29 19:00:50

标签: c# database system.reactive

我正在尝试使用ReactiveX(更确切地说,Rx.Net)和SQLite.Net构建数据访问层。

部分工作是创建一个返回数据库连接的observable,以便只在需要时才可以懒惰地打开它。这是我到目前为止所提出的:

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"));

不幸的是,每次有人订阅此observable时,都会创建一个新连接。一旦订阅被处理,它也会关闭。

我尝试使用.Replay(1).RefCount(),但它没有改变任何东西。我无论如何都不确定整个RefCount的事情。

如何将此数据库连接设为单身?

1 个答案:

答案 0 :(得分: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. 每次取消订阅或完成观察时,都会调用您的dispose / unsubscription代码。由于您正在呼叫OnCompleted,因此每次都会打开/关闭。
  2. 如果要重新使用相同的连接,则需要使用.Replay(1).RefCount()Observable.Create每次订阅者连接时都会运行整个函数,除了.Replay(1).Refcount()之外没有任何内容可以为您缓存它。
  3. 即使您添加.Replay(1).Refcount()并删除OnCompleted,如果没有未完成的订阅(例如sub2.Dispose()调用之后),您仍会处置(意味着DB-Closed)行为。< / LI>
  4. 如果您不通过using(var sub = connection.SelectMany(...))或明确地通过sub.Dispose()处理订阅,您将永远不会取消订阅,因为此Observable无法终止。换句话说,3的问题相反,你的Close代码永远不会发生。
  5. 我希望你能得到这样的结论:这是一种非常容易出错的做事方式。我建议一个简单的迭代调用,因为无论如何,这往往对数据库调用更有效。如果您坚持使用RX,我会查看Observable.Using进行数据库连接初始化。