NoSQL数据库中的模式迁移脚本

时间:2018-03-16 22:00:06

标签: c# .net mongodb azure-cosmosdb ef-migrations

我有一个一直使用C#,Entity Framework和SQL Server的活动项目。但是,随着NoSQL备选方案日益增加的可行性,我正在研究将项目转换为使用MongoDB的所有影响。

很明显,主要的过渡障碍将归因于“无架构”和#34;。在官方的MongoDB文档中找到了对C#等语言所暗示的内容的一个很好的总结here。以下是最有用的相关段落(粗体添加):

  

仅仅因为MongoDB是无架构的并不意味着您的代码可以   处理无模式文档。最有可能的是,如果你正在使用   静态类型语言,如C#或VB.NET,那么你的代码不是   灵活且需要映射到已知模式。

     

架构可以通过多种方式进行更改   你的应用程序的版本到下一个。

     

您如何处理这些取决于您自己。有两种不同的策略:   编写升级脚本。逐步更新您的文档   使用。 最简单的策略是编写升级脚本。有   实际上,关系数据库之间的这种方法没有区别   (SQL Server,Oracle)和MongoDB。识别需要的文档   被更改并更新它们。

     

或者,在大多数关系数据库中不支持,是   增量升级。这个想法是你的文件得到更新   因为他们被使用。从未使用的文档永远不会更新。   因此,你需要有一些明确的陷阱   意识到了。

     

首先,针对一半文档为版本1的架构进行查询   一半的文件是版本2可能会出错。例如,如果   你重命名一个元素,然后你的查询将需要测试旧的   元素名称和新元素名称以获得所有结果。

     

其次,任何增量升级代码必须保留在代码库中,直到   所有文件都已升级。例如,如果有的话   3个版本的文档,[1,2和3],我们删除了升级代码   从版本1到版本2,任何仍然作为版本存在的文档   1是不可升级的。

在SQL生态系统中管理/创建此类初始化或升级脚本的工具非常成熟(例如Entity Framework Migrations

虽然在NoSQL世界(similar tools)中有homemade scriptsthough some believe there should not be可用于此类升级,但似乎对""和"如何"运行这些升级脚本。 Some部署后建议。不幸的是,这种方法(当不与增量更新结合使用时)可能会在尝试读取C#模型已更改的现有数据时使应用程序处于不可用状态。

如果

  

" The easiest strategy is to write an upgrade script."

对于像C#这样的静态.NET语言,

是真正最简单/推荐的方法,是否存在用于这些语言的NoSql数据库中代码优先模式迁移的现有工具?或NoSql生态系统是不是到了那个成熟点?

如果您不同意MongoDB的建议,那么什么是更好的实现,您能否提供一些参考/示例,说明我在哪里可以看到正在使用的实现?

2 个答案:

答案 0 :(得分:4)

短版

  

是"最简单的策略是编写升级脚本。"对于像C#这样的静态.NET语言来说,它是真正最简单/推荐的方法吗?

没有。你可以这样做,但这不是NoSQL的力量。使用C#不会改变它。

  

是否存在针对这些语言的NoSql数据库中代码优先模式迁移的现有工具?

不是我意识到的。

  

或NoSql生态系统是不是到了那个成熟点?

它是无模式的。我不认为这是成熟的目标或衡量标准。

警告

首先,我相当怀疑只是将现有的关系模型推送到NoSql会在一般情况下解决比它创建的问题更多的问题。

SQL用于处理关系和数据集,noSQL用于处理非关系数据:" islands"与少数和/或软关系。两者都擅长于他们的目标,但他们擅长不同的事情。 它们不可互换。在数据重新设计,团队思维模式和应用程序逻辑变化方面做出了认真的努力,可能使大多数先前的技术设计决策失效,并且影响到建筑系统属性并可能达到用户体验。

显然,在你的情况下它可能有意义,但绝对在提交之前做ROI数学

处理架构更改

假设您确实有充分的理由进行切换,并且架构变更管理是其中的关键,我建议不要反对NoSQL的无模式特性,而是接受它。接受您的数据将具有不同的模式。

不要升级脚本

..除非您知道您的应用程序数据集永远不会增长或显着变化。 The other SO post you referenced解释得非常好。您只是无法长期依赖,因此您无论如何都需要B计划。不妨从它开始,只使用模式更新脚本,如果它对于特定情况确实更简单。

我可能会补充说明一个优秀的NoSQL优化数据模型通常针对单项搜索和写入进行优化,并且与SQL相比,批量更新可能会显着更重,即更新单个字段,您可能需要重写文档的更大部分+可能会处理一些非规范化,以减少在noSQL中查找的需要(甚至可能不是事务性的)。所以"大"在升级停机时间测量时,NoSql可能会发生明显更小并且发生速度比您预期的要快。

同时支持多个模式

同时兼容"活跃"模式版本实际上是预期的,因为无论如何都没有强制执行,这是您首先通过切换到NoSQL而购买的核心功能。

理想情况下,在noSQL思维模式中,您的逻辑应该能够处理满足特定进程所需要的任何输入数据。它应该依赖于它所需的输入而不是你的存储模型(这也使得依赖管理具有普遍意义,以降低复杂性)。也许逻辑只取决于单一类型文档中的一些属性。如果某些其他字段已更改或者添加了一些额外数据,则它不应该中断,只要它们与给定的特定工作无关。绝对不应该关心其他模型类型是否有变化。这种方法通常意味着要处理一些软价值袋(JSON / dynamic / dictionary / etc)。

即使存储模型是无模式的,那么每个业务逻辑过程都对输入模型(模式子集)有期望,并且它应该验证它可以与它给出的内容一起工作。模型中的持久模式版本号也有助于处理棘手的案例。

作为C#的人,我个人避免直接使用动态模型,而更喜欢创建一个强类型对象来包装每个动态存储类型。为了避免必须管理N个并发模式版本模型(具有最小差异)并不断升级逻辑层以支持新模式版本,我将实现它作为给定实体的所有当前支持的模式版本的超集实现您需要的任何接口。当然,您可以添加N个更多的抽象层;)一旦旧的模式版本最终从数据中逐步淘汰,您可以简化模型并获得强类型支持以覆盖所有依赖项。

此外,如果输入模型与执行预期逻辑的要求不匹配,那么逻辑层应该具有后备或反应计划非常重要。它取决于应用程序何时何地可以自动升级,接受丢弃,部分重置或必须指向一些棘手的修复队列(如果没有自动装置可以切断它,可以手动修复)或者必须直接拒绝由于不兼容而导致的请求。

是的,存在使用不同版本查询各组模型的问题,因此您应该始终考虑这些情况。您可能必须调整查询逻辑以分别查询不同版本并合并结果(如果可接受,则接受部分结果)。

肯定会有一些权衡需要考虑,当然。

那么,迁移?

缺点(如果您考虑迁移工具集可用性)是您没有一个真正的架构来自动生成模型或它的更改,因为 C#模型是源 - -truth schema 您目前正在支持。实际上,与代码优先心态非常相似,但没有迁移。

您可以实现传入的模型管道,在读取模型时自动升级模型,从而减少支持上游所需的模式版本数量。我会说这和你的移民一样接近。我不知道有任何工具可以自动为您完成此操作,而且我不确定是否会这样做。需要考虑的权衡因素,例如,一些消费数据的客户可能会使用不同的时间线进行升级等。升级到最新版可能并不总是您想要的。

结论

根据定义,NoSQL不是SQL。两者都很酷,但是期望等效性或可互换性会遇到麻烦。

你仍然需要在NoSQL中考虑和管理架构,但是如果你想要一个真正的强制执行&保证架构,然后考虑SQL。

答案 1 :(得分:1)

虽然Imre的回答非常好,但我在每个细节上都同意这一点,我想为此添加更多信息,但也试图不重复信息。

短版

如果您计划将现有的C#/ EF / SQL项目迁移到MongoDB,那么您很可能不应该这样做。它可能在一段时间内运行良好,团队知道它,并且可能已经修复了数百或更多的错误,用户或多或少对它感到满意。这是您已有的真正价值。我的意思是。由于您不应该使用新代码替换旧代码的原因,请参阅此处: https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/

与任何技术的工具的存在同样重要的是它带来价值并且它按照承诺的方式工作(工具是次要的)。

免责声明

  1. 我不喜欢mongoDB的解释,你引用了声称静态类型语言是一个问题。这是真的,但只是在一个基本的,肤浅的层面。稍后会详细介绍。

  2. 我不同意EF Code First Migration非常成熟 - 尽管它对开发和测试环境非常有用,并且它比以前的.NET数据库优先方法要好得多,但你仍然需要您自己仔细的生产部署方法。

  3. 投资自己的工具不应该成为阻碍者。事实上,如果您选择的引擎非常棒,那么就可以编写一些特定的工具。我相信伟大的团队很少使用工具"下架#34;。他们更明智地选择技术,然后根据需要定制工具或围绕它创建新工具(可能在一年或两年后销售工具)。

  4. 前线位置

    它不是静态和动态类型语言之间的。这种差异被高估了。 它更多地是关于手头的问题和架构的本质。 模式的一部分非常静态,它在静态和动态的世界中都可以很好地发挥作用。但其他部分可以随着时间的推移自然地变化,它更适合动态类型语言,但不适合它的本质。

    您可以轻松地在C#中编写具有对(列表,值)列表的代码,从而控制动态。动态类型语言给你的印象是你在C#中直接调用属性,你可以通过" key"来访问它。虽然为开发人员使用起来更容易和更漂亮,但它不会让您免于更大的问题,如部署架构更改,访问不同版本的架构等。

    因此,静态/动态语言案例根本不是问题。 更确切地说,您希望从代码(涉及任何逻辑)控制的数据和您不必严格控制的其他部分之间划一条线。第二部分不必在代码中的模式中明确而细致地表达(它可以是列表或字典而不是命名字段/属性,因为维护这些字段会花费您但不会带来任何值。)

    我的用例

    曾几何时,我的团队制作了一个使用三个不同数据库的项目:

    1. SQL for"通常"配置和证据
    2. 图形数据库,可以自然地构建任意连接对象的广泛网络
    3. 调整搜索的文档数据库(事实上是弹性搜索),使搜索即时,真正现代(如处理拼写错误等)
    4. 当然,部署如此广泛的技术堆栈是一项挑战,但每个部分都能为整个解决方案带来最佳效果。 该项目的目的是搜索任何事物(项目,人员,书籍,产品,文档,任何东西)的知识库。

      这就是为什么SQL只是为了记录可用的知识数据库列表而且#34;和分配给他们的用户。这里的模式是显而易见的,稳定而微不足道的。未来发生变化的可能性很小。

      接下来,图形数据库允许字面上"抛出"从不同来源进入数据库的任何东西,并相互连接。简单地说,这个想法是让ID可以访问对象。

      接下来,弹性搜索在此处累积ID和选定的属性子集,以使其在瞬间可搜索。这里的模式只包含ID和对列表(键,值)。

      作为最后一步,简单地说,解决方案调用Elastic Search,获取ID并显示详细信息(架构无关紧要,因为我们将其视为对键x值的列表,因此GUI准备动态构建屏幕)

      虽然解决问题的方法非常痛苦。

      我们通过运行概念证明测试了一些图形数据库,发现它们中的大多数根本不能用于更新数据等操作! (呃!!!)最后我们找到了一个足够好的DB。

      另一方面,寻找和使用弹性搜索是一件非常愉快的事情!虽然很棒,但你必须意识到,在上传海量数据的压力下它会破坏,所以你必须调整你的工具以适应它

      (所以这里没有银弹)。

      进入更广泛使用的方向

      除了我的用例之外,通常情况下你会感到极端"介于"。

      例如,文档数据库。 它可以有几乎静态的标题" ID,名称,作者等字段,您的代码可以管理它"传统上"但是所有其他领域的管理方式可以是否存在,并且可以有不同的内容或结构。

      "标题"是您决定使其与项目相关并且可由项目控制的部分。其余的是相当重要的(从项目逻辑的角度来看)。

      不同的方法

      我宁愿建议了解特定NoSQL数据库类型的优势,找到答案,为什么它们被创建,为什么它们很受欢迎和有用。然后回答他们可以为您的项目带来哪些好处。 的顺便说一句。这很有趣,为什么你指出了MongoDB?

      另一种方法是从技术角度回答您的项目当前最大的弱点或最大的挑战 - 包括性能,支持变更成本,需要显着扩展还是其他。然后尝试回答一些NoSQL DB是否能解决问题。

      结论

      我确定您可以通过替换部分数据或向用户提供新值(例如搜索?)来为项目找到NoSQL数据库的好处。无论哪种方式,我都希望有一种非常好的技术能够带来它所承诺的东西,而不是寻找它周围的工具是否完全支持它。

      此外,概念验证是一种非常好的工具,可以在非常简单但同时对您有意义的场景中检查技术。但这种方法应该不是与技术相结合,而是积极快速地证明或反驳它们的质量。

      有很多承诺和广告,我们应该通过关注有效的真实事物来保护自己。