2008-11-11 27 views
5

Angenommen, die folgende Datenschema:Ist es möglich, einen zusammengesetzten Fremdschlüssel in Schienen zu haben?

Usage 
====== 
client_id 
resource 
type 
amount 

Billing 
====== 
client_id 
usage_resource 
usage_type 
rate 

In diesem Beispiel nehme ich mehrere Ressourcen haben, von denen jeder in vielerlei Hinsicht verwendet werden können. Zum Beispiel ist eine Ressource eine widget. Widgets kann foo ed sein und sie können bar ed sein. Gizmo s kann auch foo ed und bar Ed. Diese Nutzungsarten werden mit unterschiedlichen Raten berechnet, möglicherweise sogar unterschiedlichen Raten für unterschiedliche Kunden. Jedes Auftreten einer Verwendung (einer Ressource) wird in der Verwendungstabelle aufgezeichnet. Jeder Abrechnungssatz (für die Kombination aus Kunde, Ressource und Typ) wird in der Abrechnungstabelle gespeichert.

(By the way, wenn dieses Datenschema nicht der richtige Weg ist, um dieses Problem zu nähern, bitte Vorschläge machen.)

Ist es möglich, mit Ruby on Rails und Active, eine has_many Beziehung zu schaffen von Billings zu Usages, damit ich eine Liste von Verwendungsinstanzen für einen bestimmten Abrechnungssatz erhalten kann? Gibt es eine Syntax der has_many, :through, die ich nicht kenne?

Noch einmal, ich kann dieses Problem aus dem falschen Winkel nähern, also wenn Sie sich einen besseren Weg vorstellen können, sprechen Sie bitte!

Antwort

6

Es gibt anscheinend ein Projekt bei sourceforge, um Rails ActiveRecord mit Unterstützung für Composite Primary Keys zu erweitern. Ich habe diese Erweiterung nicht verwendet, aber es könnte Ihnen helfen. Es ist auch ein Juwel in Rubyforge.

Plain Ruby on Rails unterstützt ab Version 2.0 keine zusammengesetzten Primärschlüssel (vgl. HowToUseLegacySchemas). Jede Tabelle muss einen einspaltigen Autoinkrementschlüssel mit dem Namen "id" haben.

Die Erklärung, die ich gesehen habe, ist: "Sie benötigen nur zusammengesetzte Primärschlüssel, wenn Sie eine ältere Datenbank verwenden möchten." Dies ist natürlich eine lächerlich ignorante Sichtweise der Datenmodellierung.

Die Lösung, die ich sehen würde:

  • 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

Die scheinbar redundante Fremdschlüssel in Billing Versuch Teil referentielle Integrität zu erzwingen. Aber es kommt nicht ganz dorthin - es hindert Sie nicht daran, Zeilen in Billing zu erstellen, die auf eine Zeile in Usage mit der falschen Kombination client/resource/use- type verweisen und nicht mit denen in der referenzierenden Zeile in der Fakturierungstabelle übereinstimmen.

bearbeiten: @ Yarik: ja, du hast Recht. Es macht mehr Sinn für Usage zu beziehen Billing.

  • Usage.billing_id -> Billing.id

Hmm. Ich habe ein ER-Diagramm erstellt, aber ich habe Probleme, es als Bild einzufügen.

+0

Warten Sie eine Sekunde ... Sollte es nicht das andere sein herum - ein Primärschlüssel in Billing und ein Fremdschlüssel in Usage? – Yarik

+0

Gute Antwort, guter Hintergrund. Die RoR-Ansicht von Datenbanken scheint mir problematisch. Aber das dbms scheint seine Rache dadurch erkauft zu haben, dass es RoR mit einem Ruf als langsames, nicht skalierbares Datenbankschwein belastet hat. – dkretz

1

Sie können jede gewünschte Einschränkung mit dem Befehl 'execute' in einer Migration erstellen.

Sie möchten wahrscheinlich eine Fehlerbehandlung zu .save hinzufügen, um Fälle zu behandeln, wenn die Abhängigkeit einen Fehler auslöst.

Sie können nicht ARs integrierte Methode Generatoren verwenden, um die Verbräuche von der Abrechnung zu generieren, aber Sie können immer noch die Methode:

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