10
votes

Activerecord Evier charge plusieurs appartenances

Le problème

J'ai le modèle ActiveCord suivant: p>

Person.includes(:favourite_car, :business_car, :home_car)


11 commentaires

Comment une voiture préférée diffère-t-elle une voiture d'affaires (dans le sens du modèle, c'est-à-dire)? Lorsque vous allez accéder aux données de la voiture pour une personne, avez-vous généralement besoin de trois bits (les voitures de Fave, Biz et Home)?


favourite_car, business_car et home_car sont tous des cas de voiture, il n'ya donc aucune différence dans les modèles. Presque tout le temps, j'ai besoin d'accéder à tous les trois bits ou d'aucun du tout.


Désolé ... N'a pas demandé si bien. Qu'est-ce qui différencie une voiture préférée d'une voiture à domicile (y a-t-il une colonne «Boolean» ou «type» qui différencie ces modèles)? En d'autres termes, comment savez-vous qu'une voiture est la préférée ou l'entreprise ou la maison? (Je demande vraiment une raison ... ne pas être ennuyeux :)).


Y a-t-il une raison pour une autre personne n'a pas_one au lieu d'appartenance_to? On dirait que cela serait une installation plus facile. À quoi ressemble votre structure de table?


@ Craig.kaminsky Il y a un favourite_car_id, business_car_id et home_car_id Clé étrangère dans la table des personnes, conformément aux conventions de ActiveRecord des associations d'appartenance.


Ok, merci ... juste maintenant à nouveau à la réponse de @ Franksort, qui fonctionne bien pour rencontrer la requête unique Req.


J'ai mis à jour la question avec une demi-solution, mais cela fait encore plus de questions que nécessaire lorsque cela fait inclut () chargement désireux


@CameronMartin Où avez-vous tiré que eagerloader module de? Est-ce déjà une partie du noyau des rails?


Non, c'est quelque chose que je viens de faire pour charger les associations. Seulement la moitié résout mon problème, voir le bas de mon édition.


@Engineersmnky Est-ce que vous voulez dire par exemple un has_one: via => avec une table de jointure pour chacun de favourite_car, business_car, home_car? Je ne peux pas avoir un has_one sur une personne avec un appartement_to sur une voiture, car la voiture a besoin de has_many gens_as_favourite, personnes_as_business, etc.


"Solution possible" comme vous la liste ci-dessus est mon choix de solutions. Vous ajoutez une table, mais vous retirez également 2 colonnes et la structure de données moins restrictive. La possibilité d'expansion dans le futur est bonne (que si je veux ajouter 'ma 2e voiture préférée'). Ensuite, la table de jonction fonctionnera bien.


3 Réponses :


7
votes

Essayez ceci:

> Person.all
  Person Load (0.3ms)  SELECT "people".* FROM "people"
=> #<ActiveRecord::Relation [#<Person id: 1, favorite_car_id: 1, business_car_id: 2, home_car_id: 3, name: "Frankie", created_at: "2014-02-18 21:51:58", updated_at: "2014-02-18 21:53:34">]>

> Car.all
  Car Load (0.3ms)  SELECT "cars".* FROM "cars"
=> #<ActiveRecord::Relation [#<Car id: 1, name: "Mazda", created_at: "2014-02-18 21:52:16", updated_at: "2014-02-18 21:52:16">, #<Car id: 2, name: "Honda", created_at: "2014-02-18 21:52:20", updated_at: "2014-02-18 21:52:20">, #<Car id: 3, name: "BMW", created_at: "2014-02-18 21:52:24", updated_at: "2014-02-18 21:52:24">]>

> Person.includes(:favorite_car, :business_car, :home_car).where("people.id = ?", 1).references(:favorite_car, :business_car, :home_car)
  SQL (0.4ms)  SELECT "people"."id" AS t0_r0, "people"."favorite_car_id" AS t0_r1, "people"."business_car_id" AS t0_r2, "people"."home_car_id" AS t0_r3, "people"."name" AS t0_r4, "people"."created_at" AS t0_r5, "people"."updated_at" AS t0_r6, "cars"."id" AS t1_r0, "cars"."name" AS t1_r1, "cars"."created_at" AS t1_r2, "cars"."updated_at" AS t1_r3, "business_cars_people"."id" AS t2_r0, "business_cars_people"."name" AS t2_r1, "business_cars_people"."created_at" AS t2_r2, "business_cars_people"."updated_at" AS t2_r3, "home_cars_people"."id" AS t3_r0, "home_cars_people"."name" AS t3_r1, "home_cars_people"."created_at" AS t3_r2, "home_cars_people"."updated_at" AS t3_r3 FROM "people" LEFT OUTER JOIN "cars" ON "cars"."id" = "people"."favorite_car_id" LEFT OUTER JOIN "cars" "business_cars_people" ON "business_cars_people"."id" = "people"."business_car_id" LEFT OUTER JOIN "cars" "home_cars_people" ON "home_cars_people"."id" = "people"."home_car_id" WHERE (people.id = 1)
=> #<ActiveRecord::Relation [#<Person id: 1, favorite_car_id: 1, business_car_id: 2, home_car_id: 3, name: "Frankie", created_at: "2014-02-18 21:51:58", updated_at: "2014-02-18 21:53:34">]>


7 commentaires

Cela a l'air bien mais cela fait trois jointures extérieures gauche. Ne serait-il pas préférable de faire deux questions? Chargez la personne et chargez trois voitures.


@ Andrébarbosa La question a demandé une solution avec une requête.


Sont laissés des jointures extérieures chères?


Je ne critique pas, je me demandais simplement s'il y a une solution avec de meilleures performances.


@ Andrébarbosa Je pense qu'il y a définitivement une meilleure solution. Je voudrais probablement aller avec vos deux questions, assurez-vous que mes tables étaient correctement indexées, puis travaillez sur la mise en cache et l'invalidation de cache pour les pages contenant ces données.


@Cameronmartin Entrant de gros tables peut être très chère.


J'ai posté une solution possible, mettra à jour la réponse après l'avoir testé



0
votes

Je créerai personnellement une table de jointure. Cela dit, voici une autre option: il est possible de définir une relation basée sur des requêtes SQL: xxx

alors vous pouvez faire la personne.Levreux (: voitures)


2 commentaires

Cela ne fonctionne pas. Il essaie d'exécuter la requête Sélectionnez "Voitures". * Du "voitures" où "voitures". "Person_id" dans (1, 2, 3) , où 1,2,3 sont les ID de la personne .


C'est bizarre. J'ai modifié la réponse. Pouvez-vous l'essayer à nouveau?