2008-11-11 12 views
5

Supongamos el siguiente esquema de datos:¿Es posible tener una llave foránea compuesta en los rieles?

Usage 
====== 
client_id 
resource 
type 
amount 

Billing 
====== 
client_id 
usage_resource 
usage_type 
rate 

En este ejemplo, supongamos que tengo múltiples recursos, cada uno de los cuales se pueden utilizar de muchas maneras. Por ejemplo, un recurso es un widget. Widgets puede ser foo ed y pueden ser bar ed. Gizmo s también pueden ser foo ed y bar ed. Estos tipos de uso se facturan a diferentes tasas, posiblemente incluso tarifas diferentes para diferentes clientes. Cada ocurrencia de un uso (de un recurso) se registra en la tabla de Uso. Cada tasa de facturación (para combinación de cliente, recurso y tipo) se almacena en la tabla de facturación.

(Por cierto, si este esquema de datos no es la forma correcta de acercarse a este problema, por favor, hacer sugerencias.)

¿Es posible, usando Ruby on Rails y ActiveRecord, para crear una relación has_many de Billings a Usages para que pueda obtener una lista de instancias de uso para una tasa de facturación determinada ¿Hay una sintaxis del has_many, :through que no sepa?

Una vez más, se puede abordar este problema desde el ángulo equivocado, por lo que si se puede pensar en una mejor manera, por favor, ¡habla!

Respuesta

6

Aparentemente, hay un proyecto en SourceForge para extender ActiveRecord de Rails con soporte para Composite Primary Keys. No he usado esta extensión, pero podría ayudarte. También es una joya en Rubyforge.

Llanura rubí en los carriles, a partir de la versión 2.0, no soporta claves primarias compuestas (cf. HowToUseLegacySchemas). Cada tabla debe tener una sola columna, tecla de incremento automático llamada "id".

La explicación que he visto es: "Sólo se necesita claves primarias mixtos, en caso que desee utilizar una base de datos legado". Esta es, por supuesto, una visión ridículamente ignorante del modelado de datos.

La solución que veo sería:

  • Usage.client_id -> Client.id
  • Usage.type_id -> Usagetype.id
  • Usage.resource_id -> Resource.id
  • Billing.usage_id -> Usage.id
  • Billing.client_id -> Client.id
  • Billing.type_id -> Usagetype.id
  • Billing.resource_id -> Resource.id

Las claves externas aparentemente redundantes en Billing intento de hacer cumplir la integridad referencial parcial. Pero no acaba de llegar allí - no le impide la creación de filas en Billing que hacen referencia a una fila en Usage con la combinación de cliente/recurso/usagetype mal, que no coincida con los de la fila en la tabla de referencia de facturación.

editar: @Yarik: sí, tienes razón. Tiene más sentido para Usage para hacer referencia a Billing.

  • Usage.billing_id -> Billing.id

Hmm. Hice un diagrama ER pero estoy teniendo problemas para insertarlo como una imagen.

+0

espera un segundo ... ¿No debería ser la otra a su alrededor - una clave principal en la facturación y una clave externa en el uso? – Yarik

+0

Buena respuesta, buen fondo. La vista de RoR de las bases de datos me parece problemática. Pero el DBMS parece haber exigido su venganza al sobrecargar a RoR con una reputación de ser un cerdo de base de datos lento e incalculable. – dkretz

1

Puede crear cualquier restricción que desee con el comando 'ejecutar' en una migración.

Es probable que desee agregar algún control de errores a .save para tratar casos cuando la restricción arroja un error.

No puede utilizar generadores método integrado de AR para generar los usos fuera de la facturación, pero que aún puede tener el método:

class Billing 
    def usages 
    Usage.find(:all, :conditions => ["x = ? and y = ?", self.x, self.y]) 
    end 
end 
Cuestiones relacionadas