BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

DrySQL和ActiveRecord中的ORM应用

| 作者 Bryan Evans 关注 0 他的粉丝 ,译者 刘申 关注 0 他的粉丝 发布于 2007年12月19日. 估计阅读时间: 10 分钟 | AICon 关注机器学习、计算机视觉、NLP、自动驾驶等20+AI热点技术和最新落地成功案例。

大多数面向关系的映射框架都会为你的软件(不,不是指优秀的软件)带来一些冗余。在你数据库中命名和输入的“列”却被重新命名和构造,被当成了程序代码中的实体变量。如果ORM框架为引用限制的建模提供了便利的话,这些内容会在你的数据库和应用程序代码上重复定义。许多ORM框架也会拥有一个影射层,用来定义类和数据库表格之间的映射,而这便意味着许多数据库的内容需要在3个不同的地方定义:一是数据库,二是model类,三是映射层或配置文件。

DRY(Don't Repeat Yourself,不要做重复的工作)原则的支持者建议,当逻辑相关的元素没有被同时统一改变的话,很难保持他们的同步。

“复制规范、过程或我们所开发的程序中的内容,是很容易的。但是当我们这样做的时候,恶梦便开始了”。
——Hunt & Thomas,Pragmatic开发者

你可能争辩说数据库的Schema不会经常改变,但事实却恰恰相反。我以前的一位教授曾经向我灌输“改变创造了机会”,直到有人设法反驳这个理论的时候,我还一直相信排除万难去改变是一件好事。

走进ActiveRecord

ActiveRecord是Rails的一个面向关系的映射层,目的是力图减少冗余。相比于把“列”映射成程序代码或映射文件中的实体变量,ActiveRecord是在运行中基于你的数据库Schema动态生成映射的。也就是说,类到表格(class-to-table)的映射,某一列(比如主键)和计数器都是用命名规则来识别的。

尽管ActiveRecord为ORM框架提供了很好的性能,但是仍然有很多扩展的空间,从而进一步地减少代码的冗余,并令其更具动态性。多亏了Ruby强大的灵活性和人们为RubyForgeRubyGems等项目做出的巨大努力,为现有的Ruby进行功能扩展是异常方便的。

那,需要扩展什么呢?

ActiveRecord在应用DRY原则的时候存在一些不足。如果你的表格或字段没有遵循命名规则的话,就必须在程序代码中重新定义这些数据库内容。同样,ActiveRecord的关联和校验对于数据库的约束定义来说也是一种冗余。比如我想在不更换应用程序ORM层的基础上,改变我的数据库schema。之所以要(尽量)避免更改数据库的schema,是因为如果不这样做就可能会影响到我的程序代码。

ActiveRecord通过使用数据库的定义信息来动态更新字段元数据。那么,这个策略是否可以应用到所有数据库的结构呢?

DrySQL简介

DrySQL是ActiveRecord的一个扩展,目的是让代码完全从冗余中解放出来,它完全遵循DRY原则。简单来说,它是用来为你的全部数据库schema动态建模的,并可查询它的信息schema、消除应用程序中的面向关系映射。

它是如何运作的呢?

在了解 DrySQL到底能做什么之前,很重要的一点是要知道它是在什么时候起作用的。为了给你的数据库schema建模,DrySQL需要查询你的数据库,这需要连接数据库并导致一段暂时的性能退化。为了使性能最大化和更加便利,目前的策略是从某一个表中提出元数据,先把一个类的实例映射到那个表上,用来初始化。举个例子,DrySQL从你的员工(Employee)表中提取出元数据,首先初始化一个Employee对象。然后把这些信息存在你员工类的缓存中,它对于所有Employee的子实例都是可用的。结果是,性能的降低只在(每个模型类)瞬间发生,数据库不需要连接,直到初始化模型对象时才相连,并且元数据只从与你的应用程序相关联的表格中获得。如果你的应用程序永远都不初始化Employee对象,就不会有Employee表中元数据。这个策略同样意味着开发者无须改变他们使用ActiveRecord的方式便可感受到DrySQL的好处。只要在适当的位置引入(require)DrySQL,开发者不用做任何事就能够使用它的功能。

把类映射到表格


如果你的表格名与ActiveRecord命名规则不一致,你需要用set_table_name强制把它加到模型类的定义中。这么做的唯一用途是强化命名规则的逻辑,它会令你的应用程序依然要依赖这些假设。

如果表格的名字与命名规则是一致的,那你就不用定义模型类来映射了。

如果对Employee的引用生成了一个命名错误(比如,没有定义Employee类),DrySQL会截获这个错误,并用ActiveRecord命名规则搜寻符合的表格。如果找到了一个匹配的表格,DrySQL会自动为它生成一个模型类。如果ActiveRecord::Base的基本功能就是你想添加到某个模型类中的,并且你的表格遵循ActiveRecord的命名规则,那么你跟本不用为你的表格定义模型类。

识别键

ActiveRecord会为不同的任务变量使用主键和副键,它们都是作为数据库的约束而定义的。DrySQL从你的数据库信息schema中提取这些信息,所以无论你为数据库中的字段使用什么命名规则,你都不用在程序代码中重新定义它们。下面举一些关于键使用的例子。


Find方法会查询你的Employee表中的记录,看谁的主键值为18。而不是依赖你主键字段的命名假设上,或在你的Employee类中的冗余定义(例如,set_primary_key 'X'),DrySQL从你数据库信息schema中提取雇员表中的主键。你可以为你的数据库起任何主键的名字,并且不需要在程序代码中定义。对外键来说也是同样的,就像上面那个定义了belongs_to关联一样。实际上,DrySQL会自动生成关联、外键和所有的东西。

生成关联与校验

DrySQL会提取表格中的约束定义,并用它们自动生成模型类的关联。多数情况下,基于相关的约束生成关联是很容易的,前提是你的数据库schema是用公认的方式来定义的。然而间接关联(through association)则是一种例外。如果A has_many B与 [X, Y, Z]间接关联,那么很难去决定应该生成哪一个关联。每一个从A到B的关联都会覆盖前面一个,这些关联必须依赖处理约束的顺序。尽管还算不上完美,不过DrySQL通过拒绝用间接关联重写现有的关联,减轻了问题的复杂性。如果开发者想解决A has_many B through=> [X, Y, Z]的问题,他们可以在模型类中定义想要的间接关联,并且DrySQL也希望你这么做。DrySQL也会给直接关联高于间接关联的优先权,所以间接关联是永远不会覆盖掉直接关联的,例如belongs_to或has_many。

许多ActiveRecord校验都是与数据库的约束相对应的,并且DrySQL会自动生成校验。DrySQL致力于准确的模仿数据库约束的某些行为,validates_nullabillity_of就是一个很好的例子。这种校验会通过拒绝空值,强迫加上非空[NOT NULL]字段的约束,但是也只有在这种情况下,你的数据库会拒绝空值。举例来说,如果你的字段是自动生成的,或者设有某个默认值,validates_nullability_of将不会拒绝空值,因为你的数据库本身在这个时候就不拒绝空值。

总结

ActiveRecord是以一种创新的方式使用数据库的schema,并自动创建表格和字段的映射。DrySQL把这种策略应用到了数据库中的其他结构上,它的最终目标是将所有数据库的结构只定义在一个地方:数据库自身。关于DrySQL更多的信息,请查看RubyForge上的项目主页

关于作者

Bryan Evans是一位软件工程师,为多伦多的一个大型财务公司效力,非常擅长软件架构。Bryan作为DrySQL的开发者,是一个长期的Smalltalk开发者,并对Ruby的ActiveRecord非常感兴趣。

查看英文原文:ORM with DrySQL and ActiveRecord
译者简介:刘申(网名x5),现为哈尔滨工业大学信息管理与信息系统专业在读研究生,对Web前端开发、Ruby on Rails以及极限编程十分感兴趣,曾参与多本Web开发相关书籍的翻译。参与InfoQ中文站内容建设,请邮件至china-editorial[at]infoq.com

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT