【问题标题】:Rails & Postgres: Join tables on an arrayRails 和 Postgres:在数组上连接表
【发布时间】:2018-09-28 20:15:03
【问题描述】:

从概念上讲,我想做的是能够说:产品 a 有 5 种颜色可供选择,这将是一组颜色 ID。这些颜色 id 是链接到颜色表的键,颜色表包含颜色相关数据,例如十六进制表示、彩色图像等。最后,我想将颜色表与产品表连接起来,以便提取颜色相关数据。

在我当前的设置中,我有两个表:productscolors。在我的 products 表中,我有一列 (color_ids) 包含一个整数数组。此数组保存colors 表中colors 的ID。为了在 Rails 中加入这两者,我在 Product 类中创建了一个自定义 SQL 字符串,例如:

class Product < ApplicationRecord
  has_many :colors

  def self.custom_query   
    "SELECT * FROM products JOIN colors on colors.id = ANY(products.color_ids)
    WHERE products.name = 'Some Product'"
  end

end

我尝试使用关联 (includes(:colors)) 但这似乎不起作用,因为主 ID 是一个 ID 数组。

有没有更优雅的 / Rails 方式来实现我想要做的事情?

【问题讨论】:

    标签: ruby-on-rails postgresql associations


    【解决方案1】:

    使用简单的has_and_belongs_to_many 关联。不要将您的参考 id 存储在数组中,仅仅因为 PostgreSQL 允许您这样做,这不是关系数据库中应该如何实现关系。

    # new migration
    create_table :colors_products do |t|
      t.references :color, foreign_key: true
      t.references :product, foreign_key: true
    end
    add_index :colors_products, [:color_id, :product_id], unique: true
    
    
    class Product < ApplicationRecord
      has_and_belongs_to_many :colors
    end
    
    class Color < ApplicationRecord
      has_and_belongs_to_many :products
    end
    

    所有的 ActiveRecord 方法都将起作用。

    为什么不应该与数组建立关系(除非你真的知道你在做什么):

    1. 您不能使用外键。您将能够在您的数组中拥有一个不再在数据库中的 color_id。
    2. 如果您删除一种颜色,您的数据库将无法自动清除所有产品的 ID。
    3. ActiveRecord(和大多数 ORM)根本无法工作,您需要大量的变通方法。

    【讨论】:

    • 您的答案的这个问题(不是真正的问题)是每次我想访问颜色信息时,Rails 都需要打开与数据库的连接。我希望优化 db hits,以便 Rails 只打开一次连接来检索所有需要的数据。另外,为什么不应该出于好奇而按照我的方式实施关系?我的方式是每种颜色只有一行。另一种方法是每一种新颜色都需要一个额外的行,然后如果你添加尺寸,它会成倍地变大。
    • 您可以通过调用includes 使用预先加载以避免N+1 查询。我将在原始答案中添加问题。
    • 这就是我最初尝试做的事情,例如Product.includes(:colors) 但由于 color_ids 在 products 表中的数组中,我收到错误消息。如果您可以在不更改数组类型的情况下找到解决方法,那么这就是我正在寻找的答案。
    • includes 是一个非常复杂的方法,它决定是否应该通过左连接进行预加载是附加查询。我强烈建议您在为时已晚之前转身,否则您将与 ActiveRecord 进行一场非常艰苦的战斗:(包含问题将是众多问题之一,但您当然可以尝试。
    • 哈哈我同意。我这样做更多是出于好奇。感谢您的帮助!
    【解决方案2】:

    你可以这样做

    class Product < ApplicationRecord
      def colors   
        Color.where(id: color_ids)
      end
    end
    
    class Color < ApplicationRecord
      def products   
        Product.where('? = Any (category_ids)', id)
      end
    end
    

    【讨论】:

      猜你喜欢
      • 2017-12-17
      • 1970-01-01
      • 2019-02-04
      • 1970-01-01
      • 2013-02-28
      • 2021-03-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      相关资源
      最近更新 更多