20

只是为了扩展我的知识,我开始研究各种 NoSQL 选项。我访问的第一个是 RavenDB,它看起来很有趣。我仍在尝试打破我根深蒂固的关系思维,以及典型的 RDBMS 维护例程。

在我与实体框架打交道的日常工作中,我们经历了编写 DB 更改脚本、刷新 EF 映射模型等的例行程序。它在 NoSQL 的东西(尤其是 RavenDB)中是如何工作的?一旦一个应用程序运行起来,如何对各种 POCO 对象等进行更改并将其部署到生产环境中?存储在旧 POCO 类中的数据会怎样?

我还没有深入研究或愤怒地使用过 Raven DB。一旦我这样做,这可能很明显,但我很想事先知道,所以我不会把自己编码到角落里。

感谢:D。

4

4 回答 4

28

它们保持原样 - 不再存在的属性在加载时将被忽略(并在更改时丢失),丢失的属性将返回为空,

建议您使用基于集合的操作来使数据与对象模型保持一致。

哦,看看我,我现在在电脑上!

基本上是这样,在迁移到文档存储时,您正确地认识到您失去了一些功能并获得了一些自由,因为在数据库中您定义了一个预先定义的模式并尝试上传与该模式不匹配的数据将导致错误。

然而,重要的是要认识到,无模式和无结构之间存在差异,因为您的文档都包含它们自己的结构(表示属性名称和属性值的键/值对)。

这对于编写一些代码并保持数据持久化的整个“刚刚开始”因素很有用 - 但是当你很容易改变你的代码结构时,它可能更难与你已经持久化的数据相协调。

在这一点上出现了一些策略:

  • 一旦你有持久化数据,让你的结构不可变,版本你的类
  • 允许修改结构,但使用基于集合的操作来更新数据以匹配新结构
  • 允许修改结构,并编写代码处理加载数据时的不一致

第三个显然是个坏主意,因为它会导致无法维护的代码,如果您只是存储事件或其他此类数据,则对您的类进行版本控制可以工作,但实际上并不适合大多数情况,所以您只剩下中间了选项。

我建议您这样做,并遵循一些简单的规则,就像您在处理关系数据库中的前期模式时所遵循的那样。

  • 使用您的 VCS 系统确定已部署版本之间的更改
  • 编写从一个版本升级到另一个版本的迁移脚本
  • 注意重命名/删除属性 - 因为如果新文档中不存在这些属性,加载文档和保存文档将导致数据丢失

等等。

我希望这更有帮助:-)

于 2011-01-23T22:12:30.867 回答
3

RavenDB 将您的 .NET 对象序列化为 JSON 格式。没有架构。

如果您将一些对象添加到数据库中,它们将被序列化。如果您将一些属性添加到您正在序列化的类型,您已经存储的对象将缺少这些属性。

于 2011-01-23T22:13:06.373 回答
3

Ayende 的这篇文章描述了如何执行从版本 1 到版本 2 的迁移(在这种情况下,将“Name”属性更改为“FirstName”和“LastName”属性。

http://ayende.com/blog/66563/ravenb-migrations-rolling-updates

基本上,在 DocumentStore 中注册了一个侦听器:

documentStore.RegisterListener(new CustomerVersion1ToVersion2Converter())

从上述文章中提取的示例执行:

public class CustomerVersion1ToVersion2Converter : IDocumentConversionListener
{
    public void EntityToDocument(object entity, RavenJObject document, RavenJObject metadata)
    {
        Customer c = entity as Customer;
        if (c == null)
            return;

        metadata["Customer-Schema-Version"] = 2;
        // preserve the old Name property, for now.
        document["Name"] = c.FirstName + " " + c.LastName;
        document["Email"] = c.CustomerEmail;
    }

    public void DocumentToEntity(object entity, RavenJObject document, RavenJObject metadata)
    {
        Customer c = entity as Customer;
        if (c == null)
            return;
        if (metadata.Value<int>("Customer-Schema-Version") >= 2)
            return;

        c.FirstName = document.Value<string>("Name").Split().First();
        c.LastName = document.Value<string>("Name").Split().Last();
        c.CustomerEmail = document.Value<string>("Email");
    }
}
于 2013-12-18T10:57:47.750 回答
2

您没有架构管理,而是将其移入代码中,因此代码中的对象与数据库中的对象之间永远不会不匹配。

处理更改的第一部分是确保您使用可以处理缺失/额外值的序列化程序 - 如果数据中未定义字段,请将其设置为 null。如果数据中的字段与对象的属性不匹配,请忽略它。

大多数更改都可以处理,除此之外 - 要么有一个新字段,但无论如何您都需要为现有记录设置一个默认值,或者有一个您不再关心的旧字段。

对于更复杂的更改,例如重命名/组合字段或更改数据格式,向您的对象添加一个新字段而不删除旧字段,并让您的加载方法从旧字段传输数据。当您保存记录时,它将采用新格式。此代码可以永久保留,根据需要更新数据,或者您可以设置一次性流程为所有现有对象调用相同的代码。请注意,与 sql 脚本不同,即使在大型数据集上运行需要很长时间,这种类型的更新也不需要停机,因为代码可以处理新旧格式。

于 2011-01-24T00:55:52.117 回答