Pregunta

Tengo un escenario que no es fácil de explicar, pero estoy seguro de que es un problema muy común. Haré mi mejor esfuerzo para ilustrar el problema.

Digamos que tenemos una aplicación de encuesta que nos permite crear encuestas. Cada encuesta tiene su propia estructura (contiene preguntas, las preguntas se agrupan y ordenan, etc.). Esas encuestas son administradas por un administrador y se denominan plantillas maestras de encuesta. Ahora el usuario puede seleccionar una de esas encuestas maestras, realizar algunas personalizaciones y realizar la encuesta en algunas personas.

Entonces, básicamente tenemos encuestas que comparten la misma estructura (colecciones, propiedades, etc.) pero los datos pueden ser diferentes.

¿Cómo se modela la base de datos?

Mi idea sería almacenar todo en una tabla y crear una columna que separe las plantillas de las realizadas.

tbl_Survey (id, name, conducted_on)

¿Cómo modelas tus clases?

Mi idea sería:

Survey {
  Name
  Questions
}

ConductedSurvey : Survey {
  //gets the master according to the name
  GetMaster()
}

Importante: una encuesta tiene muchas relaciones con otras clases. Si decidimos subclase. ¿Deberían clasificarse todos ellos (porque copiaríamos los datos del maestro para cada objeto)?

¿Fue útil?

Solución

  

Entonces, básicamente tenemos encuestas que comparten la misma estructura (colecciones, propiedades, etc.) pero los datos pueden ser diferentes ... Mi idea sería almacenar todo en una tabla y crear una columna que separe las plantillas de los realizados.

Bueno, de lo que estás hablando es de un prototipo. La " plantilla " La encuesta es un prototipo. Claramente, si un prototipo tiene exactamente la misma estructura que una instancia basada en el prototipo, sería una tontería y un desperdicio crear tablas completamente diferentes para la misma estructura, tanto más cuando se da cuenta de que eso significa cualquier cambio en esa estructura. tiene que reflejar en ambos conjuntos.

¿Agregaría una columna para distinguir un prototipo / plantilla de una encuesta realizada? No, probablemente no. En su lugar, agregaría otra tabla, con una relación de uno a uno con la tabla de la encuesta raíz. En esta tabla, agregaría un poco de metadatos que distinguen un prototipo de un no prototipo.

Por tres razones: 1) en cualquier sistema razonable, los prototipos serán una pequeña minoría de las encuestas totales. 2) A menudo me gustaría enumerar todos los prototipos, por ejemplo, en un " crear nuevo asistente de encuesta " que enumera una selección de protoypes en los cuales basar la nueva encuesta. Y 3) para guardar un poco de datos adicionales:

create table survey_prototype (
    id int not null primary key,
    survey_id references survey(id) -- the regular survey table
    wizard_description varchar(80)
    . . . .
);

Ahora, me imagino que la encuesta también tiene una descripción, pero que para un prototipo, esa descripción es algo como: "REEMPLAZAR ESTA ES LA DESCRIPCIÓN QUE EL USUARIO VERÁ " pero esa wizard_description es algo así como "un prototipo de encuesta política".

Ahora, ya que cualquier búsqueda de un prototipo / plantilla no tiene posibilidad de devolver una encuesta realizada (ya que ninguna encuesta realizada se une a survey_prototype), su aspecto de getMaster (conceptualmente, probablemente use un ORM) así:

ConductedSurvey : Survey {
  //gets the master according to the name
  GetMaster() { "select * from survey_prototype join survey..."
}
  

Importante: una encuesta tiene muchas relaciones con otras clases. Si decidimos subclase. ¿Deberían clasificarse todos ellos (ya que copiaríamos los datos del maestro para cada objeto)?

Usted tiene razón: para cualquier prototipo que recupere a través de su ORM, tendrá que hacer una copia profunda para guardar una nueva encuesta en lugar de sobrescribir el prototipo. Como tienes que hacer la copia profunda de todos modos, en la copia profunda puedes, en lugar de ocultar la clase base que usa el prototipo, hacer una copia de subclase.

Por supuesto que tendrá que tomar esa decisión en cada nivel de la jerarquía; Sería bueno encapsular cada política de transformación para una transformación de copia profunda en una clase. Visitor Pattern hará esto, ya que tiene una función sobrecargada de visit por clase (base) de sus tipos: así (al menos) visitSurvey , visitQuestion , visitAnswer .

Ya que estará tratando con un árbol (enraizado en la encuesta, con preguntas de niños y respuestas de nietos, es decir, Patrón compuesto), le sugiero que use el Patrón de visitante en su copia / transformador. Ya que sus clases son relativamente estables, el visitante trabajará bien. Y le permite tener múltiples visitantes concretos, uno para cada tipo de transformación (y cuando llega el momento de mostrar o puntuar una encuesta, también puede escribir un visitante para esa funcionalidad), por lo que obtendrá esa funcionalidad casi " de forma gratuita " una vez que haya configurado el Patrón de visitante).

Para manejar la subclasificación en la base de datos, puede utilizar cualquiera de los patrones de inhibición comunes para esto; de esa manera, una vez que haya visitado y transformado, tendrá un nuevo árbol de levantamiento no prototipo que se puede guardar en la base de datos "automáticamente".

Para resumir: survey_prototype table, obtenga un prototipo, nhibernate recuperará todo el árbol cuando solicite la raíz en survey_prototype, visite ese árbol con un transformador de copia profunda que devuelva la raíz copiada, deje que el usuario escriba en eso , guarde la raíz copiada y deje que nhibernate recursivamente guarde todos los nodos del árbol. Cuando el usuario necesite ver la encuesta no prototipo, extraiga la raíz de la encuesta con nhibernate, use el visitante de pantalla para mostrarla, etc.

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