2

在 RavenDB 中使用 URL 作为键的最佳方式是什么?

不幸的是,更新项目的语义在文档中并不清楚:如果键以反斜杠结尾,它总是一个插入,否则如果键已经存在,它可能是一个更新。

但是URL 可以以斜线结尾,而RavenDB 使用终止斜线来生成密钥

RavenDB 还支持身份的概念,例如,如果您需要连续的 ID。通过在实体中创建字符串 Id 属性,并将其设置为以斜杠 (/) 结尾的值,您可以告诉 RavenDB 将其用作实体的键前缀。在您调用 SaveChanges() 后,该前缀后跟下一个可用的整数 ID 将是您的实体 ID。并且该正斜杠无法重新配置。所以它并没有真正“支持”它,而是强制执行它。

编辑:同一个 RavenDB 文档页面说明了以下内容,这与观察到的行为不对应:

您可以为文档分配您可以想象的任何 ID。一切都会正常工作,但是您必须注意,当具有自定义生成 ID 的文档数量非常多(数百万个文档)时,某些类型的 ID 可能会导致性能问题。

选项包括: 1. 修改您的 url 以删除结尾斜杠 2. Url 对 url 进行编码(如 RavenDB 维护人员所建议的那样) 3. 修改架构并使用数据库生成的 ID

在大多数情况下,选项 1 应该是安全的。选项 2 会使密钥不可读,而且我还没有设法使其工作(可能是 RavenDB 或我的代码中的错误)。选项 3 似乎不必要地使架构复杂化。

一般来说,最好的行动方案是什么?

4

3 回答 3

3

我想这是一个偏好问题——但我认为 URL 不是很好的键。其他人不同意。请参阅支持论坛上的此讨论。

我会认真考虑为什么需要它作为键,以及是否可以索引 url。例如:

public class Site
{
    public string Id { get; set; } // such as "sites/1"
    public string Name { get; set; }
    public string Url { get; set; }
}

var q = session.Query<Site>().Where(x=> x.Url == "http://foo/bar");

使用它作为键的理由是 URL 应该唯一地表示资源,但是当您考虑 http 与 https、可选的查询字符串参数等时,情况并非总是如此。

此外,RavenDB 文档键不区分大小写,而 URL(通常)区分大小写。许多 Web 服务器会忽略基本 url 上的大小写,但仍然由 Web 应用程序决定如何对查询字符串参数区分大小写或不区分大小写。http://foo/bar?q=abc所以它完全有可能http://foo/bar?q=ABC引用两个独立的资源,但在 Raven 中它们将被视为相同的文档键。

如果您觉得必须使用 URL 作为文档键,那么正如 Ayende 所说,您应该以某种方式转义它们,可能像这样:

// to escape
var key = Uri.EscapeDataString(url);


// to unescape
var url = Uri.UnescapeDataString(key);

我确信还有其他转义或编码格式也可以,这似乎是最简单的一种。

于 2013-02-12T15:24:21.367 回答
1

如果要将 URL 用作文档键,则需要对 URL 进行转义。

于 2013-02-12T13:32:34.527 回答
1

让我在这里从一个从业者的角度来插话。我必须将 OpenIds 作为文档键存储在 RavenDb 中,所以很自然地出现了这个问题。虽然最近的版本已经修复了与作为文档键的逃逸 URL 有关的问题,但我仍然不推荐它,因为我遇到了各种错误。我报告了其中一些,它们得到了修复,但我最终放弃了。

我首先开始在 URL 上使用 base64 编码,但很快发现这可能会导致超过 RavenDb 限制的长文档键,并且您会看到服务器端 Esent ColumnTooBig 异常。

由于这些 ID 变得太长(合法的 URL 可能长达 2000 个字符),我已经开始使用它们的 base64 编码的 SHA-Hashes。不能说它很优雅,但它工作得很好。

于 2013-09-18T09:17:04.980 回答