如何从数据库中播种observable

时间:2014-03-26 08:45:04

标签: c# .net system.reactive reactive-programming

我试图公开一个可观察的序列,该序列为观察者提供数据库表中的所有现有记录以及任何未来的项目。为了争论,我们可以说它的日志条目。因此,我有这样的事情:

public class LogService
{
    private readonly Subject<LogEntry> entries;

    public LogService()
    {
        this.entries = new Subject<LogEntry>();

        this.entries
            .Buffer(...)
            .Subscribe(async x => WriteLogEntriesToDatabaseAsync(x));
    }

    public IObservable<LogEntry> Entries
    {
        get { return this.entries; }
    }

    public IObservable<LogEntry> AllLogEntries
    {
        get
        {
            // how the heck?
        }
    }

    public void Log(string message)
    {
        this.entries.OnNext(new LogEntry(message));
    }

    private async Task<IEnumerable<LogEntry>> GetLogEntriesAsync()
    {
        // reads existing entries from DB table and returns them
    }

    private async Task WriteLogEntriesToDatabaseAsync(IList<LogEntry> entries)
    {
        // writes entries to the database
    }
}

我对AllLogEntries实施的初步想法是这样的:

return Observable.Create<LogEntry>(
    async observer =>
    {
        var existingEntries = await this.GetLogEntriesAsync();

        foreach (var existingEntry in existingEntries)
        {
            observer.OnNext(existingEntry);
        }

        return this.entries.Subscribe(observer);
    });

但问题是,可能会记录已缓冲但尚未写入数据库的条目。因此,这些条目将被遗漏,因为它们不在数据库中并且已经通过entries可观察对象。

我的下一个想法是将缓冲的条目与非缓冲的条目分开,并在实现AllLogEntries时使用缓冲:

return Observable.Create<LogEntry>(
    async observer =>
    {
        var existingEntries = await this.GetLogEntriesAsync();

        foreach (var existingEntry in existingEntries)
        {
            observer.OnNext(existingEntry);
        }

        return this.bufferedEntries
            .SelectMany(x => x)
            .Subscribe(observer);
    });

这有两个问题:

  1. 这意味着AllLogEntries的客户端在收到日志条目之前还必须等待缓冲区时间跨度。我希望他们能够即时查看日志条目。
  2. 还有一个竞争条件,即日志条目可以在我读完现有条目的点和我将来的条目返回点之间写入数据库。
  3. 所以我的问题是:我怎样才能真正实现我的要求,不存在竞争条件,避免任何重大的性能损失?

1 个答案:

答案 0 :(得分:0)

要通过客户端代码执行此操作,您可能必须使用轮询实现解决方案,然后查找调用之间的差异。可能将解决方案与

结合起来

会给你足够的解决方案。

或者,我建议您尝试找到一个解决方案,在更新数据库/表时通知客户端。在Web应用程序中,您可以使用SignalR之类的东西来执行此操作。

例如:http://techbrij.com/database-change-notifications-asp-net-signalr-sqldependency

如果它不是Web应用程序,则通过套接字的类似更新机制可能有效。

请参阅这些链接(这些链接来自SignalR polling database for updates的接受答案):