【问题标题】:Realm .NET Where query with Contains() throws System.NotSupportedExceptionRealm .NET Where 使用 Contains() 查询抛出 System.NotSupportedException
【发布时间】:2021-05-13 03:52:45
【问题描述】:

我正在使用 Realm for .NET v10.1.3,并且我有一个删除一些对象的方法。从表明支持 Contains 的文档中提取,我有以下 sn-p:

var results = realm.All<DeviceEventEntity>()
    .Where(entity => ids.Contains(entity.Id));
                            
realm.RemoveRange(results);

但是当realm.RemoveRange(results) 被执行时,Realm 会抛出一个 System.NotSupportedException。我在这里做错了什么?还是 Realm 不支持 Contains?

这是堆栈跟踪:

System.NotSupportedException
The method 'Contains' is not supported
   at Realms.RealmResultsVisitor.VisitMethodCall(MethodCallExpression node) in C:\jenkins\workspace\realm_realm-dotnet_PR-2362@2\Realm\Realm\Linq\RealmResultsVisitor.cs:line 378
   at Realms.RealmResultsVisitor.VisitMethodCall(MethodCallExpression node) in C:\jenkins\workspace\realm_realm-dotnet_PR-2362@2\Realm\Realm\Linq\RealmResultsVisitor.cs:line 164
   at Realms.RealmResults`1.CreateHandle() in C:\jenkins\workspace\realm_realm-dotnet_PR-2362@2\Realm\Realm\Linq\RealmResults.cs:line 65
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at Realms.RealmResults`1.get_ResultsHandle() in C:\jenkins\workspace\realm_realm-dotnet_PR-2362@2\Realm\Realm\Linq\RealmResults.cs:line 30
   at Realms.Realm.RemoveRange[T](IQueryable`1 range) in C:\jenkins\workspace\realm_realm-dotnet_PR-2362@2\Realm\Realm\Realm.cs:line 1279
   at DocLink.Client.Storage.Service.Event.DeviceEventService.<>c__DisplayClass2_0.<DeleteEvents>b__0() in

这里有一个更完整的例子:

public Task DeleteEvents(List<ObjectId> ids) {
  return Task.Run(() => {
    using (var realm = GetRealm()) {
      using (var transaction = realm.BeginWrite()) {
        try {
          var results = realm.All<DeviceEventEntity>().Where(entity => ids.Contains(entity.Id));
          realm.RemoveRange(results);
          transaction.Commit();
        }
        catch (Exception exception) {
          transaction.Rollback();
          throw new ServiceException("Unable to delete events. Transaction has been rolled back.", exception);
        }
      }
    }
  });
}

此外,库引用像 C:\jenkins\workspace\realm_realm-dotnet_PR-2362@2\Realm\Realm\Linq\RealmResultsVisitor.cs 这样的文件似乎有点奇怪。这不是我系统上的任何东西,库是通过 NuGet 拉入的。

【问题讨论】:

标签: c# realm


【解决方案1】:

文档说遇到NotSupportedException 时需要使用Filter。阅读有关方法的 cmets 以获得指向 NSPredicate 备忘单的链接,您可以使用它做很多事情:)

【讨论】:

  • 所以你是说我可以在 C# 中使用 NSPredicate 语法?
  • 是的,我从 Realm .NET github 中提取了它。如果它不起作用,那么我们需要向他们提出问题
  • 看看他们的一个单元测试here
  • 因此,只要我有一个可以使用的常量表达式,过滤器方法似乎就可以工作。 Realm 在其谓词查询中一直支持替换变量,甚至您指出的单元测试也显示了同样多的内容,但在我的 IDE 中,它只显示了一个带有单个参数(谓词字符串)的 Filter() 方法。
【解决方案2】:

更新问题。首先,感谢所有参与并帮助我指明正确方向的人。最终的答案最终是几件事的结合,但简而言之,正是这个previous post 最终解决了这个问题。

当前版本的 Realm 支持 Mongo ObjectId,但是在 Filter() 方法中使用 ObjectId 并没有真正起作用。所以解决方法是最终使用字符串作为 PK,但在 DTO 中使用 ObjectId——在输出时转换为 ObjectId,在进入 Realm 时转换为 ToString()。

public static class IQueryableExtensions {
    public static IQueryable<T> In<T>(this IQueryable<T> source, string propertyName, IList<ObjectId> objList)
        where T : RealmObject {
        var query = string.Join(" OR ", objList.Select(i => $"{propertyName} == '{i.ToString()}'"));
        var results = source.Filter(query);

        return results;
    }
}

我的代码使用了扩展

public Task DeleteEvents(List<ObjectId> ids) {
        return Task.Run(() => {
            using (var realm = GetRealm())
            {
                using (var transaction = realm.BeginWrite())
                {
                    try {
                        // In order to support this with the current version of Realm we had to write an extension In()
                        // that explodes the list into a Filter() expression of OR comparisons. This also required us
                        // to use string as the underlying PK type instead of ObjectId. In this way, our domain object
                        // still expects ObjectId, so we ToString() on the way into realm and ObjectId.Parse() on the
                        // way out to our DTO.
                        var results = realm.All<DeviceEventEntity>().In("Id", ids);
                        realm.RemoveRange(results);
                        transaction.Commit();
                    }
                    catch (Exception exception)
                    {
                        transaction.Rollback();
                        throw new ServiceException("Unable to delete events. Transaction has been rolled back.", exception);
                    }
                }
            }
        });
    }

【讨论】:

    猜你喜欢
    • 2013-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多