Pregunta

Me preguntaba cuál es la mejor manera de modelar una relación donde un objeto está asociado con exactamente n objetos de otra clase. Quiero extender la relación has_one a un valor específico de n.

Por ejemplo, una TopFiveMoviesList pertenecería al usuario y tendría exactamente cinco películas. Me imagino que la tabla sql subyacente tendría campos como movie_id_1, movie_id_2, ... movie_id_5.

Sé que podría hacer una relación has_many y limitar el número de niños a nivel de modelo, pero prefiero no tener una tabla intermedia.

¿Fue útil?

Solución

Mi primer instinto sería usar una tabla de unión, pero si eso no es deseable, las columnas User.movie [1-5] _id encajarían en la factura. (Creo que movie1_id encaja mejor con la convención de Rails que movie_id_1 .)

Dado que etiquetó este Rails y ActiveRecord, agregaré un código de modelo completamente no probado y probablemente algo incorrecto a mi respuesta. :)

class User < ActiveRecord::Base
  TOP_N_MOVIES = 5
  (1..TOP_N_MOVIES).each { |n|  belongs_to "movie#{n}".to_sym, :class_name => Movie }
end

Podrías envolver esa línea en un método de estilo macro, pero a menos que sea un patrón común para tu aplicación, hacerlo probablemente hará que tu código sea más difícil de leer con poco beneficio DRY.

También es posible que desee agregar validaciones para asegurarse de que no haya películas duplicadas en la lista de un usuario.

Asociar su clase de película a sus usuarios es similar.

class Movie < ActiveRecord::Base

  (1..User::TOP_N_MOVIES).each do |n| 
    has_many "users_list_as_top_#{n}".to_sym, :class_name => User, :foreign_key => "movie#{n}_id"
  end

  def users_list_as_top_anything
    ary = []
    (1..User::TOP_N_MOVIES).each {|n| ary += self.send("users_list_as_top_#{n}") }
    return ary
  end

end

(Por supuesto que users_list_as_top_anything probablemente se escribiría mejor como SQL explícito. Hoy estoy perezoso.)

Otros consejos

Creo que implementar este modelo a través de un modelo de combinación será la mejor opción aquí. Permite que el modelo List se preocupe por la lógica de lista y el modelo Movie para preocuparse por la lógica de la película. Puede crear un modelo Nomination (el nombre no es el mejor, pero sabe a lo que me refiero) para manejar la relación entre películas y listas, y cuando hay un límite de 5, puede limitar el cantidad de nominaciones que retira.

Hay algunas razones por las que creo que este enfoque es mejor.

Primero, suponiendo que desea poder atravesar las relaciones en ambos sentidos ( movie.lists y list.movies ), el enfoque de 5 columnas será mucho más desordenado.

Si bien sería mucho mejor para ActiveRecord admitir tiene n relaciones, no lo hace, por lo que estará luchando contra el marco en ese sentido. Además, la relación has n me parece un poco frágil en esta situación. No he visto este tipo de implementación ejecutada en ActiveRecord, aunque estaría realmente interesado en que esto suceda. :)

Supongo que te refieres a " implementar " en lugar de "modelo" El modelado es bastante fácil en UML, por ejemplo, donde tienes una entidad Person que se compone de 5 entidades Movie.

Pero la dificultad viene cuando dices has_one, yendo a has_5. Si es un valor escalar simple, has_one es quizás una propiedad en la entidad principal. Has_5 es probablemente 2 entidades relacionadas entre sí a través de un " se compone de " relación en UML.

La pregunta principal a responder es probablemente, " ¿Puede garantizar que siempre será 'Top 5'? " En caso afirmativo, modele con columnas, como mencionó. Si no, modele con otra entidad.

Otra pregunta es quizás: "¿Qué tan fácil será refactorizar?" Si es simple, diablos, comience con 5 columnas y refactorice para separar las entidades si alguna vez cambia.

Como de costumbre, " mejor " depende del entorno comercial y técnico.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top