我需要帮助重新编写一个最初用 Squeel 编写的额外数据库查询,我尝试了各种语法,但似乎无法理解

Posted

技术标签:

【中文标题】我需要帮助重新编写一个最初用 Squeel 编写的额外数据库查询,我尝试了各种语法,但似乎无法理解【英文标题】:I need help re writing one additional DB Query originally written with Squeel, I tried various syntax but can't seem to get it 【发布时间】:2021-11-20 23:01:21 【问题描述】:

我需要帮助重新编写一个额外的数据库查询,该查询最初是使用名为 Squeel 的 gem 编写的。这个使用的语法与其他的略有不同,我认为我可以调整我所拥有的,但它似乎不起作用。

我一直在将一个名为 Emissions Gateway 的应用程序从 Rails v3.2 重写到 Rails v6.1.4.2。数据库查询是我一直卡住的地方。

这里是 Squeel 查询:

Project.joinsvendor.joinscertifications.outer.where
       (projects.vendor_id.eq my vendor_id ) |
       (vendors.parent_vendor_id.eq my vendor_id ) |
       ((certifications.donaldson == true) & (certifications.published == true))
     .uniq

这是控制台外的 Rails v3.2 SQL。

SELECT DISTINCT "vendors".* FROM "vendors" 
INNER JOIN "projects" ON "projects"."vendor_id" = "vendors"."id" 
INNER JOIN "certifications" ON "certifications"."project_id" = "projects"."id" 
WHERE (("certifications"."donaldson" = 't' AND "certifications"."published" = 't')) 
ORDER BY "vendors"."parent_vendor_id", "vendors"."name"

我试过了:

Project.joins(vendor: :certifications).where(certifications:  donaldson: 't', published: 't' )
.order(:parent_vendor_id, :name)

我试过了:

Project.joins(:vendor, :certifications).where(certifications:  donaldson: 't', published: 't' )
.order(:parent_vendor_id, :name)

Project.rb 模型(只是关联部分和架构信息)

# == Schema Information
#
# Table name: projects
#
#  id                :integer          not null, primary key
#  vendor_id         :integer
#  fleet_id          :integer
#  status            :string(255)      default("incomplete")
#  created_at        :datetime         not null
#  updated_at        :datetime         not null
#  user_id           :integer
#  notes             :text
#  user_verified_id  :integer
#  user_submitted_id :integer
#  certified         :boolean
#  cached_user_name  :string(255)
#  deleted           :boolean          default(FALSE)
#  cached_fleet_name :string(255)
#
class Project < ActiveRecord::Base
  attr_accessible :status, :fleet_id, :vendor_id, :notes, :user_verified_id, :user_created_id, :user_submitted_id, :certified, :user_id, :engine_completed, :vehicle_completed, :inspection_completed, :maintenance_completed, :deleted, :cached_fleet_name, :cached_user_name, :cached_vehicle_number

  has_one :assessment, dependent: :destroy
  has_one :controlled_sale, dependent: :destroy
  has_one :datalogger, dependent: :destroy
  has_one :estimate, dependent: :destroy
  has_many :audits, dependent: :destroy
  has_many :certifications, dependent: :destroy
  has_many :filters, through: :certifications
  has_many :kits, through: :certifications
  has_many :pictures, dependent: :destroy
  has_many :warranties, dependent: :destroy
  has_many :work_orders, dependent: :destroy

  belongs_to :fleet
  belongs_to :user, touch: true
  belongs_to :vendor
  belongs_to :verified_by, :class_name => "User", :foreign_key => "user_verified_id"
  belongs_to :submitted_by, :class_name => "User", :foreign_key => "user_submitted_id"

  delegate :status, :complete?, to: :datalogger, prefix: true, allow_nil: true
  delegate :name, to: :vendor, prefix: true
  delegate :name, to: :user, prefix: true, allow_nil: true
  delegate :name, to: :verified_by, prefix: true, allow_nil: true
  delegate :name, to: :submitted_by, prefix: true, allow_nil: true

  before_create :cache_associated_data
  before_update :cache_user_name, :if => :user_id_changed?
  before_update :cache_fleet_name, :if => :fleet_id_changed?
  after_create :audit_create
  after_update :audit, :if => :status_changed?
  after_update :audit_reassignment, :if => :user_id_changed?
  after_update :audit_destroy, :if => :vendor_id_changed?
  after_update :devalidation_notice, :if => :certified_changed?
  after_update :locking_detection, :if => :status_changed?
  after_update :prepared_notice, :if => :status_changed?

  validates_presence_of :vendor_id
  validates_presence_of :user_id, :unless => :deleted?
  validates_presence_of :fleet_id, :unless => :deleted?

vendor.rb 模型 Schema 和关联js:

# == Schema Information
#
# Table name: vendors
#
#  id                :integer          not null, primary key
#  name              :string(255)
#  address           :string(255)
#  contact           :string(255)
#  email             :string(255)
#  phone             :string(255)
#  note              :string(255)
#  user_manager_id   :integer
#  created_at        :datetime         not null
#  updated_at        :datetime         not null
#  logo_file_name    :string(255)
#  logo_content_type :string(255)
#  logo_file_size    :integer
#  logo_updated_at   :datetime
#  parent_vendor_id  :integer
#  street            :string(255)
#  street2           :string(255)
#  city              :string(255)
#  state             :string(255)
#  zip               :integer
#  country           :string(255)
#  region            :string(255)
#

class Vendor < ActiveRecord::Base
  attr_accessible :name, :phone, :contact, :email, :street, :street2, :city, :state, :zip, :country, :logo, :note, :addresses_attributes, :parent_vendor_id, :user_manager_id, :region_id, :users_attributes

  has_many :articles
  has_many :projects, dependent: :destroy
  has_many :fleets, dependent: :destroy
  has_many :users, dependent: :destroy
  has_many :subvendors, foreign_key: "parent_vendor_id", class_name: 'Vendor'
  has_many :verifications, dependent: :destroy
  has_one :subscription, dependent: :destroy
  alias_method :original_subscription, :subscription

  # certain regions are restricted to select subvendors
  has_many :regions
  # this vendors region
  belongs_to :region

  belongs_to :manager, foreign_key: "user_manager_id", class_name: 'User'
  belongs_to :parent_vendor, foreign_key: "parent_vendor_id", class_name: 'Vendor'
  belongs_to :fleet, touch: true

  # CHANGED (allow_blank:true removed) v0.005 9/2/2021 Scott Milella
  # delegate :name, to: :manager, prefix: true, allow_blank: true, allow_nil: true
  # delegate :name, to: :region, prefix: true, allow_blank: true, allow_nil: true
  delegate :name, to: :manager, prefix: true, allow_nil: true
  delegate :name, to: :region, prefix: true, allow_nil: true


  before_validation :sanitize

  validates_presence_of :phone, :email, :street, :city, :state, :zip, :country
  validates_presence_of :contact, message: "name for owner cannot be blank"
  validates_presence_of :name, message: "of company can't be blank"
  validates_presence_of :region_id, :if => :region_required?

  validates :name, exclusion:  in: ['donaldson', 'diesel emissions service', 'trash'] 

  validates_format_of :phone,
      :message => "must be a valid telephone number.",
      :with => /[0-9]10|[(]1[0-9]0,3[) -]0,3?[0-9]3[ -]0,4?[0-9]4/

  accepts_nested_attributes_for :users, reject_if: :all_blank

带有架构和关联信息的certification.rb 模型:

# == Schema Information
#
# Table name: certifications
#
#  id         :integer          not null, primary key
#  project_id :integer
#  filter_id  :integer
#  kit_id     :integer
#  created_at :datetime         not null
#  updated_at :datetime         not null
#  published  :boolean          default(FALSE)
#

class Certification < ActiveRecord::Base
  belongs_to :project, touch: true
  belongs_to :filter
  belongs_to :kit
  attr_accessible :project_id, :filter_id, :donaldson, :cdti, :published, :published_at
  validates_uniqueness_of :filter_id, scope: :project_id

我添加了模型,因为每当我尝试执行以下操作时都会遇到错误: Project.joins(vendor: :certifications) 我收到一个错误:

Can't join 'Certification' to association named 'vendor'; perhaps you misspelled it? 

当我查看认证模型时,它似乎与供应商没有关系,它属于项目。

当我查看供应商模型时,它有很多项目

当我查看 Project 时,它似乎是与两者都有关联的项目,它有很多 :certifications,它属于 :vendor

我尝试了很多方法来告诉 Rails 到 Project.joins(vendor: :certifications) 但它总是给我一个项目试图加入这两个表的错误,但存在关系并且显然它以某种方式使用 Squeel宝石?语法问题?

任何帮助将不胜感激,我相信这是这个应用程序的最后一个问题,我已经完成了。 先感谢您, 斯科特

【问题讨论】:

【参考方案1】:
Vendor
       .joins(:projects, :certifications)
       .where(
          certifications:  
            # use a boolean and let the DB adapter cast it
            donaldson: true, 
            published: true 
          
       )
       .order(:parent_vendor_id, :name) 
       .destinct

【讨论】:

啊你想要.joins(:vendor, :certifications) SQL使用vendors.name.order("vendors.parent_vendor_id", :name)会生成projects.name 不,它没有。您不必在 `.and(...)` 段中重复整个查询。我只会看 SQL 而不是 sqeel 代码,这简直是疯了。我仍然不明白哪种巫术将块中传递给 where 的这三个表达式变成了两个连接和 where 子句的ON 条件。就像他们打破了整个 Ruby 语言并从燃烧的残骸中构建了一个 DSL。 几乎正确。它缺少DESTINCT 啊,对了,如果你想选择供应商之外的行而不是项目,你应该基于供应商的查询。

以上是关于我需要帮助重新编写一个最初用 Squeel 编写的额外数据库查询,我尝试了各种语法,但似乎无法理解的主要内容,如果未能解决你的问题,请参考以下文章

Ruby Gem Squeel,如何编写自联接

如何直接编译最初用 code::blocks 编写的代码

Ruby Squeel 库弃用核心扩展

QFile 和 QTextStream 帮助(使用用户名、密码和名称为用户编写 ID)

Squeel 子查询

Squeel load_core_extensions 的弃用警告