多has_many :through关联问题:如何查询特定卖家的所有Purchase记录
首先得理清楚当前的模型关联逻辑:你的Purchase现在可以关联到Game或者UnlimitedGame,而这两个商品模型都属于coach(这里要注意,你的Seller模型和coach的关联看起来可能存在笔误?比如是不是Game和UnlimitedGame应该belongs_to :seller?如果是笔误的话,调整后关联会更顺畅,下面我先基于你给出的现有模型来给出方案)。
要查询特定卖家的所有Purchase记录,有几种可行的方式:
1. 在Seller模型中扩展关联,合并两种来源的订单
你可以在Seller模型里分别关联两种商品的订单,再合并成一个统一的purchases方法:
class Seller # 先确保Seller和Game、UnlimitedGame的关联正确(如果Game/UnlimitedGame的belongs_to是coach,这里可能需要调整为has_many :games, through: :coaches之类的,或者确认Seller就是Coach模型) has_many :games, through: :coaches has_many :unlimited_games, through: :coaches # 分别关联两种商品的订单 has_many :game_purchases, through: :games, source: :purchases has_many :unlimited_game_purchases, through: :unlimited_games, source: :purchases # 合并两种订单 def purchases # 更高效的单SQL查询方式 Purchase.where(game_id: games.pluck(:id)).or(Purchase.where(unlimited_game_id: unlimited_games.pluck(:id))) end end
这样之后,你就可以直接用seller.purchases获取该卖家的所有订单了。
2. 直接编写查询语句(无需修改模型)
如果你不想修改Seller模型,也可以在查询时直接构造条件:
# 假设你已经拿到了目标卖家对象@seller game_ids = @seller.games.pluck(:id) unlimited_game_ids = @seller.unlimited_games.pluck(:id) # 一次性查询所有符合条件的Purchase all_purchases = Purchase.where(game_id: game_ids).or(Purchase.where(unlimited_game_id: unlimited_game_ids))
3. 用自定义SQL关联(进阶方式)
你也可以直接在Seller模型里定义一个自定义的has_many关联,用SQL子查询来关联订单:
class Seller has_many :purchases, ->(seller) { where( "game_id IN (SELECT id FROM games WHERE coach_id = ?) OR unlimited_game_id IN (SELECT id FROM unlimited_games WHERE coach_id = ?)", seller.id, seller.id ) }, dependent: :destroy end
这种方式的好处是可以直接使用seller.purchases,而且是单SQL查询,性能较好,但要注意SQL语法的兼容性。
重要提示
从你的模型定义来看,Game和UnlimitedGame都是belongs_to :coach,但你的Seller模型是通过games来关联订单的——这里很可能是模型关联的笔误。如果Seller就是商品的拥有者,那应该把Game和UnlimitedGame的belongs_to :coach改成belongs_to :seller,这样关联逻辑会更清晰,上面的代码也可以简化(比如去掉through: :coaches的部分)。
内容的提问来源于stack exchange,提问作者anonn023432

