反应性(“ Rx”)方式来缓存和更新数据

时间:2019-05-02 16:42:19

标签: c# reactive-programming system.reactive

我有一个例程,该例程从db读取数据,并通过IObservable发布该数据。

发布数据后,我想更新所有刚发布的行,以阻止它们再次发布。

我不确定这样做的“反应性”方式。 (每次我重新访问Rx时,我似乎都遇到了这个问题!)

我认为我需要做两件事

1)在发布时缓存数据,因为它将具有我随后需要更新的ID-我想知道是否要使用主题来缓存要发布的数据,或者是否要使用其他一些包裹我的例程当前拥有,订阅它,缓存它,然后重新发布

2)发布数据后更新数据。我真的不确定如何将其构建到管道中!

我已经从网上发现的各种内容中构建了这个数据库(特别是数据库轮询的Lee Campbell-Lee!),但是我添加的其他内容是我的,我可能做得不好错误。如果某些部分可以更好地实现非反应性,我愿意提出建议。例如,我已经使db update例程可观察到,但是我不知道它是否真的必要-或者如果以这种方式实现,是否更容易将其包含在管道中。

下面是相关的代码...

private IObservable<INotification> Poller() =>
    Observable
        .Timer(_pollingPeriod, _scheduler)
        .SelectMany(_ => NewNotifications(_cx))                
        .Timeout(_pollingPeriod + _queryTimeout, Observable.Return(TimeOut.Notification()), _scheduler) 
        .Catch<INotification, Exception>(err => Observable.Return(Error.Notification(err))) 
        .Repeat();  

private IObservable<INotification> NewNotifications(string cx)
{
    try
    {                
        return SqlRead<INotification>(cx, NewNotificationsSql(),sdr => EventBuilder(sdr), Empty.Notification());
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

internal static IObservable<T> SqlRead<T>(string cx, string sql, Func<SqlDataReader, T> mapper, T noRows) =>
    Observable.Create<T>(o =>
    {                
        using (var conn = new SqlConnection(cx))
        {
            conn.Open();
            using (var cmd = new SqlCommand(sql, conn))
            {                        
                using (var rdr = cmd.ExecuteReader())
                {
                    if (!rdr.HasRows)
                    {
                        o.OnNext(noRows);
                    }
                    else
                    {
                        while (rdr.Read())
                        {             
                            o.OnNext(mapper(rdr));                                    
                        }
                    }
                }
            }
        }
        o.OnCompleted();                
        return Disposable.Empty;
    });

internal static IObservable<int> SqlWrite(string cx, string sql) =>
    Observable.Create<int>(o =>
    {
        using (var conn = new SqlConnection(cx))
        {
            conn.Open();
            using (var cmd = new SqlCommand(sql, conn))
            {
                o.OnNext(cmd.ExecuteNonQuery());
            }                    
        }
        o.OnCompleted();
        return Disposable.Empty;
    });

1 个答案:

答案 0 :(得分:1)

让我们假设您有一个包含当前通知列表的用户界面

public class NotificationListViewModel
{
    ObservableCollection<INotification> Items {get;}
}

要维护此集合,您需要了解通知的更改方式。 让我们来展示变化的课程

enum ChangeType
{
   Add,
   Remove,
   Update
}

class Change<T>
{
    ChangeType Type {get;}
    T Value {get;}
}

现在您可以通过更改公开通知

INotificationProvider
{
   public IObservable<Change<INotification>> Notifications {get;}
}

为了方便起见,请在Update中添加方法INotification

public class NotificationListViewModel
{
    public NotificationListViewModel(INotificationProvider provider)
    {
        provider.Notifications.Subscribe(change => 
        {
          if(change.Type == ChangeType.Add)
          {
            Items.Add(change.Value);
          }
          if(change.Type == ChangeType.Update)
          {
            Items.First(x => x.Id = change.Value.Id).Update(change.Value);
          }
          if(change.Type == ChangeType.Remove)
          {
            Items.Remove(change.Value);
          }
        });
    }
}

要了解收到的更改的类型,您需要维护从数据库读取通知的现有通知列表。

我编写的所有这些代码均显示了“您如何考虑这些事情”的示例。 有一个很棒的库DynamicData,所有这些想法都以便捷且优化的方式实现。