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