字符串 Id

这是我遇到的最常见的请求之一,所以就有了这篇教程。

Isar 原生不支持字符串 Id,这是经过深思熟虑的:原因是整型 Id 比字符串 Id 性能更好。尤其是在处理关联上,使用字符串 Id 会显著增加额外的性能开销。

我理解,有时候你需要存储一些使用 UUID 或非整型 Id 的数据。我建议将这些字符串 Id 作为对象的属性,并用其快速散列化后的 64 位整型作为 Isar 对象的 Id。

@collection
class User {
  String? id;

  Id get isarId => fastHash(id!);

  String? name;

  int? age;
}

通过这个办法,你既可以高效地使用整型 Id 来处理关联,又保留了原有数据中的字符串 Id。

快速散列函数

理想情况下,你的散列函数应该兼具高可用性(没人希望崩溃或意外发生)和高性能。我推荐使用下方代码实现:

/// 针对 Dart 字符串优化的 64 位哈希算法 FNV-1a
int fastHash(String string) {
  var hash = 0xcbf29ce484222325;

  var i = 0;
  while (i < string.length) {
    final codeUnit = string.codeUnitAt(i++);
    hash ^= codeUnit >> 8;
    hash *= 0x100000001b3;
    hash ^= codeUnit & 0xFF;
    hash *= 0x100000001b3;
  }

  return hash;
}

如果你选择其他散列函数,确保它返回 64 位整型,避免使用加密散列函数,因为它们非常慢。

警告

避免使用 string.hashCode,因为无法保证它能够适用于各个平台,或适配各个版本的 Dart。