在查询中自定义生成的选择?[花岗岩ORM]



我正在尝试在旧数据库(使用现有数据&表结构(上在琥珀(使用花岗岩ORM(中构建加入查询,并想知道是否可以自定义选择选择。从查询的一部分来支持跨桌连接。

这是一个名为vehicles的表的当前表结构:

-----------------------------------------------
| vehicleid | year | makeid | modelid |
-----------------------------------------------
| 1 | 1999 | 54 | 65 |
| 2 | 2000 | 55 | 72 |
| ... | ... | ... | ... |
-----------------------------------------------

等。

其中makeidmodelidmakesmodels表的外键参考。在这些表中是命名列(分别为makenamemodelname(。

我正在尝试生成一个加入查询以吸引名称:

SELECT vehicle.yearid, make.makename AS make, model.modelname AS model FROM vehicles JOIN....

(删除加入详细信息(。

因此,当查询返回时,我有一个Vehicle对象,并且可以访问:

Vehicle.yearid

Vehicle.make

Vehicle.model

使用花岗岩可以吗?

我可以通过使用RAW SQL获得查询的加入部分以生成,但是我不知道如何自定义表&选择部分中的列名。我尝试过创建一个对象:

class Vehicle < Granite::ORM::Base
  adapter pg
  primary vehicleid : Int32
  field yearid : Int32
  field make : String
  field model : String
end

但是花岗岩正在生成以下SQL:

SELECT vehicle.yearid, vehicle.make, vehicle.model FROM vehicle JOIN...

这是因为vehicle.makevehicle.model实际上存在错误。

我想要的是这个SQL:

SELECT vehicle.yearid, make.makename AS make, model.modelname AS model FROM vehicles JOIN....

有没有办法做这项工作?

根据这个问题,花岗岩尚未具有一对一的关系,但作者提到使用has_many宏来定义一种调用该方法来调用该方法宏定义的方法,但返回该方法返回的数组中的第一个元素(因为它只能是一个元素(。

首先,您需要为另外两个表modelmake创建模型:

class Model < Granite::ORM::Base
  adapter pg
  belongs_to :vehicle
  primary modelid : Int32
  field modelname : String
end
class Make < Granite::ORM::Base
  adapter pg
  belongs_to :vehicle
  primary makeid : Int32
  field makename : String
end

如果您的字段不仅仅是modelnamemakename,请务必添加这些字段。

最后,您需要在原始Vehicle类中添加has_many关系,并定义makemodel方法:

class Vehicle < Granite::ORM::Base
  adapter pg
  primary vehicleid : Int32
  field yearid : Int32
  has_many :makes
  has_many :models
  def make
    makes.first["makename"]
  end
  def model
    models.first["modelname"]
  end
end

查询就像:

一样简单
vehicle = Vehicle.find 2
puts vehicle.model

不幸的是,我不相信花岗岩尚未支持列别名(AS(,而无需完全绕过ORM,因此您必须明确返回这些列(上面的代码所做的(或直接使用vehicle.model["modelname"]

注意:我可能会发现花岗岩返回的哈希的类型,因为它们的源代码没有任何类型的注释,并且完全依赖Crystal的类型推理,这使得很难导航。但是我认为这是{} of String => DB::Any,但我可能错了。如果收到编译器错误,请尝试使用Symbol而不是String

感谢@svenskunganka给了我一个想法,我想到了这条路线,我想出了一个靠近RAW SQL的花岗岩精神的解决方案对象。

我在模型定义中添加了sql类方法,该方法几乎与all相同,但剥离了更多的结构。为了支持它,我还必须在PG适配器中添加新的query方法,但现在适用于我的用例。这是猴子绘制的代码:

class Granite::Adapter::Pg < Granite::Adapter::Base
  def query(statement = "", params = [] of DB::Any, &block)
    statement = _ensure_clause_template(statement)
    log statement, params
    open do |db|
      db.query statement, params do |rs|
        yield rs
      end
    end
  end
end
module Granite::ORM::Querying
  def sql(clause = "", params = [] of DB::Any)
    rows = [] of self
    @@adapter.query(clause, params) do |results|
      results.each do
        rows << from_sql(results)
      end
    end
    return rows
  end
end

有点丑

vehicles = Vehicle.sql("SELECT vehicle.vehicleid, vehicle.yearid, make.makename AS make, 
model.modelname AS model FROM vehicle JOIN ...<snip>")

我可以做类似的事情:

vehicles.each do |v| 
  puts "#{v.yearid} #{v.make} #{v.model}"
end

它的工作原理。

相关内容

  • 没有找到相关文章

最新更新