【问题标题】:Realm search in async function and use the result in main thread异步函数中的领域搜索并在主线程中使用结果
【发布时间】:2017-12-04 11:13:51
【问题描述】:

我需要根据关键字对我的一个 Realm 表执行搜索。搜索功能是在异步函数中完成的,但速度很慢:搜索并显示 9000 条数据的结果需要 3-5 秒。

搜索分三步完成:

  • 根据查询搜索并返回Guid列表
  • 根据 Guid 列表返回对象列表
  • 使用结果值更新 UI

当我尝试直接从SearchIssueInProject 返回List<IssueTable> 时,我以后无法访问它的属性,因为“此领域实例已关闭”(类似的)。

这是我的搜索功能:

public async Task<List<IssueTable>> GetFilteredIssuesInProject(string query)
{
     if (!string.IsNullOrEmpty(query))
     {
          var searchResults = await Task.Run(() => SearchIssueInProject(query));
          return searchResults.Select(i => RealmConnection.Find<IssueTable>(i)).ToList();
     }

     return this.AllIssuesInProject;
}

List<string> SearchIssueInProject(string query)
{
     using (var realm = Realm.GetInstance(RealmConfiguration))
     {
          Func<IssueTable, bool> searchIssue = d =>
                            string.IsNullOrEmpty(query) ? true :
                            Contains(d.Id.ToString(), query) ||
                            Contains(d.Status.DisplayName, query) ||
                            Contains(d.Status.Value, query) ||
                            Contains(d.Team.Name, query) ||
                            Contains(d.Team.Initial, query) ||
                            Contains(d.StandardIssueCategory.Title, query) ||
                            Contains(d.StandardIssueType.Title, query) ||
                            Contains(d.Drawing.Title, query) ||
                            Contains(d.Location.Title, query) ||
                            Contains(d.CreatedBy.DisplayName, query) ||
                            Contains(d.UpdatedBy.DisplayName, query);

          var result = realm.All<IssueTable>().Where(searchIssue)
                                  .OrderByDescending(i => i.UpdatedDate)
                                  .Select(i => i.Guid)
                                  .ToList();

          return result;
     }
}

        public List<IssueTable> GetAllIssues()
        {
            return RealmConnection.All<IssueTable>()
                            .OrderByDescending(i => i.UpdatedDate)
                            .ToList();
        }

包含功能:

public static bool Contains(string source, string filter)
{
     return source.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
}

这就是我使用搜索功能的方式:

this.WhenAnyValue(x => x.ViewModel.IssueSearchQuery)
    .Throttle(TimeSpan.FromMilliseconds(1000), RxApp.MainThreadScheduler)
    .DistinctUntilChanged()
    .Do(_ =>
     {
         this.IssueAdapter.Issues.Clear();
     })
    .Select(searchTerm =>
     {
         if (SearchingProgressDialog == null && Activity != null)
         {
              ShowLoadingProgress();
         }
         var result = this.ViewModel.GetFilteredIssuesInProject(searchTerm);
          return result
                       .ToObservable()
                       .ObserveOn(RxApp.MainThreadScheduler);
      })
     .Switch()
     .Subscribe(searchResult =>
      {
          this.IssueAdapter.Issues.AddRange(searchResult);
          this.IssueAdapter.NotifyDataSetChanged();
          if (SearchingProgressDialog != null)
          {
               SearchingProgressDialog.Dismiss();
               SearchingProgressDialog = null;
          }
      });

如何改进搜索功能?

【问题讨论】:

    标签: multithreading xamarin xamarin.android realm reactiveui


    【解决方案1】:

    因为你创建的是一个函数而不是一个表达式,所以查询不是由 Realm 评估的,而是由 LINQ to objects 这意味着每个对象都需要由 Realm 获取,然后访问的属性将被获取一个一个供比较使用。不幸的是,您搜索的所有字段都需要遍历 Realm .NET 尚不支持的相关对象。

    解决此问题的一种方法是将数据非规范化并将这些属性复制到IssueTable 对象上。然后你可以执行如下查询:

    var result = realm.All<IssueTable>()
                      // Note that the .Where overload we select uses Expression<Func<>>
                      // Also, StatusDisplayName is a copy of Status.DisplayName
                      .Where(i => i.StatusDisplayName || ...)
                      .OrderByDescending(i => i.UpdatedDate)
                      .ToArray()
                      .Select(i => i.Guid)
                      .ToList();
    

    【讨论】:

    • 这意味着我需要在IssueTable 对象上添加更多属性,它仍然需要两步搜索:(1)获取 Guid 列表和(2)根据 Guid 列表检索对象。有没有办法让它成为一个步骤?
    • 您应该能够创建对查询的线程安全引用。类似:var query = realm.All&lt;IssueTable&gt;().Where(...).OrderByDescending(...);,然后创建一个 tsr:var queryReference = ThreadSafeReference.Create(query);。然后在主线程上,你可以做var query = realm.ResolveReference(queryReference);。查看文档了解更多详情:realm.io/docs/dotnet/latest/#passing-instances-across-threads
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 2016-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多