8

我试图了解通过面向对象的构建器 DSL 构建 SQL 与参数化原始 SQL 字符串的好处。在以三种方式研究/实现相同的查询之后,我注意到原始 SQL 是迄今为止最容易阅读的。这就引出了一个问题,“为什么要跳过篮筐?” 为什么不直接声明和使用原始 SQL?

这是我想出的:

首先,我猜它使 SQL 更便携,因为它可以被任何带有适配器的数据库使用。我想这是大佬吧?不过,大多数数据库不是可以理解大多数 T-SQL 吗?

其次,它提供了一个可以重用的查询对象——作为其他查询、命名范围链接等的基础。

通过构建 SQL 而不是声明它,您实现的主要投资回报是什么?

def instances_of_sql(ttype_id) #raw sql
  ttype_id = get(ttype_id).try(:id)
  ti   = get('tmdm:type-instance')
  inst = get('tmdm:instance')
  type = get('tmdm:type')

  self.class.send :sanitize_sql, [%{
    SELECT t.*
    FROM associations a
    JOIN roles type    ON type.association_id = a.id AND type.ttype_id = ?
    JOIN roles inst    ON inst.association_id = a.id AND inst.ttype_id = ?
    JOIN topics t      ON t.id = inst.topic_id
    WHERE a.topic_map_id IN (?)
    AND a.ttype_id    = ?
    AND type.topic_id = ?
  }, type.id, inst.id, self.ids, ti.id, ttype_id]
end

def instances_of_sql(ttype_id) #sequel
  ttype_id = get(ttype_id).try(:id)
  ti = get('tmdm:type-instance')
  ir = get('tmdm:instance')
  tr = get('tmdm:type')

  DB.from(:associations.as(:a)).
    join(:roles.as(:tr), :tr__association_id => :a__id, :tr__ttype_id => tr[:id]).
    join(:roles.as(:ir), :ir__association_id => :a__id, :ir__ttype_id => ir[:id]).
    join(:topics.as(:t), :t__id => :ir__topic_id).
    where(:a__topic_map_id => self.ids).
    where(:a__ttype_id => ti[:id]).
    where(:tr__topic_id => ttype_id).
    select(:t.*).sql
end

def instances_of_sql(ttype_id) #arel
  ttype_id = get(ttype_id).try(:id)
  ti   = get('tmdm:type-instance')
  inst = get('tmdm:instance')
  type = get('tmdm:type')

  #tables
  t    = Topic.arel_table
  a    = Association.arel_table
  tr   = Role.arel_table
  ir   = tr.alias

  a.
    join(tr).on(tr[:association_id].eq(a[:id]),tr[:ttype_id].eq(type[:id])).
    join(ir).on(ir[:association_id].eq(a[:id]),ir[:ttype_id].eq(inst[:id])).
    join(t).on(t[:id].eq(ir[:topic_id])).
    where(a[:topic_map_id].in(self.ids)).
    where(a[:ttype_id].eq(ti[:id])).
    where(tr[:topic_id].eq(ttype_id)).
    project('topics.*').to_sql
end

我非常欣赏命名范围,并了解将它们链接起来是如何有益的。我不担心通过模型访问相关记录。我纯粹是在谈论构建一个复杂的查询。

4

2 回答 2

8

@Kyle Heironimus 提供给 Nick Kallen 对 Arel 的想法的链接有这样一行:

您将注意到子选择中派生表的使用。在我看来,这太可怕了。只有高级 SQL 程序员知道如何写这个(我在工作面试中经常问这个问题,我从未见过有人做对)。而且应该不难!

好吧,Kallen 将此归结为 SQL 组合下缺乏封闭性。在某些情况下这可能是真的,但我的经验要平淡得多——大多数开发人员都不擅长 SQL。他们只知道最基本的东西,当他们试图在基于集合的语言中搜索程序解决方案时,这些基本的东西被误用了。在我所在的一家公司,我不得不与所有其他开发人员争论数据库在 3NF 中的好处,他们只是没有得到它。有才华的人(他们中的大多数:),但对 SQL 或数据库一无所知。

将它放在 C# 或 Ruby 或 Python <插入选择的语言> 中,开发人员再次感到高兴。他们可以坚持过程/OO 思维并生成对他们来说看起来不错的代码。

我知道这不会为我赢得任何选票,可能恰恰相反,但这是我的观点。顺便说一句,Arel 看起来很有趣。


作为我上面评论的补充,六个月过去了,在那段时间里用了很多 Sequel 库,我可以说它确实是一个美丽的东西,现在我觉得我会提前使用它使用直接 SQL。它不仅功能强大,让我可以做简单和高级的事情而不会让人头疼(总会有一些),它可以输出它使用过的 SQL,如果我还可以让我进入 SQL觉得我需要。

这绝不会否定我对大多数开发人员对 SQL 的理解的评论,(我最近被一位与其他人交谈的开发人员告知,规范化是存储空间昂贵的时代的遗物......哦,亲爱的!)只是Sequel库的开发显然是由真正了解数据库的人完成的。如果您了解 SQL 和数据库设计等,那么它可以更快地为您提供更多功能。我不能对我使用过的其他 ORM 说同样的话,但也许其他人会有不同的想法。

于 2011-02-10T20:17:58.537 回答
4

你已经很清楚原因了。

以下是 Arel 的创建者的想法。

于 2011-02-10T19:57:58.290 回答