2010-05-30 8 views
7

Ich bin auf Multi-Tenancy-Datenbank-Schema-Design für ein SaaS-Konzept. Es wird ASP.NET MVC -> EF sein, aber das ist nicht so wichtig.Entity Framework und Multi-Tenancy-Datenbank-Design

Unten sehen Sie ein Beispiel für ein Datenbankschema (der Mieter ist das Unternehmen). Die CompanyId wird im gesamten Schema repliziert, und der Primärschlüssel wurde sowohl auf den natürlichen Schlüssel als auch auf die Tenant-ID gesetzt.

dieses Schema in das Entity Framework Anstecken gibt die folgenden Fehler, wenn ich die Tabellen in das Entity Model-Datei (Model1.edmx) hinzufügen:

  • Die Beziehung ‚FK_Order_Customer‘ verwendet den Satz von Fremdschlüssel '{CustomerId, CompanyId}', die teilweise in der Menge der Primärschlüssel '{OrderId, CompanyId}' der Tabelle 'Order' enthalten sind. Die Gruppe von Fremdschlüsseln muss vollständig in der Menge der Primärschlüssel enthalten sein oder nicht vollständig in der Menge der Primärschlüssel enthalten sein, die einem Modell zugeordnet werden sollen.
  • Die Beziehung 'FK_OrderLine_Customer' verwendet die Menge der Fremdschlüssel '{CustomerId, CompanyId}', die teilweise im Satz der Primärschlüssel '{OrderLineId, CompanyId}' der Tabelle 'OrderLine' enthalten sind. Die Gruppe von Fremdschlüsseln muss vollständig in der Menge der Primärschlüssel enthalten sein oder nicht vollständig in der Menge der Primärschlüssel enthalten sein, die einem Modell zugeordnet werden sollen.
  • Die Beziehung 'FK_OrderLine_Order' verwendet die Gruppe der Fremdschlüssel '{OrderId, CompanyId}', die teilweise in der Menge der Primärschlüssel '{OrderLineId, CompanyId}' der Tabelle 'OrderLine' enthalten sind. Die Menge der Fremdschlüssel muss vollständig in der Menge der Primärschlüssel enthalten sein oder nicht vollständig in der Menge der Primärschlüssel enthalten sein, die einem Modell zugeordnet werden sollen.
  • Die Beziehung 'FK_Order_Customer' verwendet die Gruppe der Fremdschlüssel '{CustomerId, CompanyId}', die teilweise in der Menge der Primärschlüssel '{OrderId, CompanyId}' der Tabelle 'Order' enthalten sind. Die Menge der Fremdschlüssel muss vollständig in der Menge der Primärschlüssel enthalten sein oder nicht vollständig in der Menge der Primärschlüssel enthalten sein, die einem Modell zugeordnet werden sollen.
  • Die Beziehung 'FK_OrderLine_Customer' verwendet die Menge der Fremdschlüssel '{CustomerId, CompanyId}', die teilweise im Satz der Primärschlüssel '{OrderLineId, CompanyId}' der Tabelle 'OrderLine' enthalten sind. Die Menge der Fremdschlüssel muss vollständig in der Menge der Primärschlüssel enthalten sein oder nicht vollständig in der Menge der Primärschlüssel enthalten sein, die einem Modell zugeordnet werden sollen.
  • Die Beziehung 'FK_OrderLine_Order' verwendet die Gruppe der Fremdschlüssel '{OrderId, CompanyId}', die teilweise in der Menge der Primärschlüssel '{OrderLineId, CompanyId}' der Tabelle 'OrderLine' enthalten sind. Die Gruppe von Fremdschlüsseln muss vollständig in der Menge der Primärschlüssel enthalten sein oder nicht vollständig in der Menge der Primärschlüssel enthalten sein, die einem Modell zugeordnet werden sollen.
  • Die Beziehung 'FK_OrderLine_Product' verwendet die Menge der Fremdschlüssel '{ProductId, CompanyId}', die teilweise in der Menge der Primärschlüssel '{OrderLineId, CompanyId}' der Tabelle 'OrderLine' enthalten sind. Die Menge der Fremdschlüssel muss vollständig in der Menge der Primärschlüssel enthalten sein oder nicht vollständig in der Menge der Primärschlüssel enthalten sein, die einem Modell zugeordnet werden sollen.

Die Frage ist in zwei Teilen:

  1. meine Datenbank-Design falsch sind? Sollte ich auf diese zusammengesetzten Primärschlüssel verzichten? Ich stelle meine Vernunft bezüglich des grundlegenden Schemadesigns (Frazzled Brain Syndrome) in Frage. Bitte zögern Sie nicht, das "idealisierte" Schema vorzuschlagen.
  2. Wenn das Datenbankdesign korrekt ist, kann EF dann die Schlüssel nicht zuordnen, da es diese Fremdschlüssel als potenziell falsch konfigurierte 1: 1-Beziehungen (falsch) wahrnimmt? In welchem ​​Fall ist das ein EF-Bug und wie kann ich damit umgehen?

Multi-tenancy database schema http://i46.tinypic.com/23si52u.png

+0

Wenn ich die zusammengesetzten Primärschlüssel entferne und einfach die natürlichen Schlüssel (ProductId, OrderId, CustomerId, OrderLineId) verwende, verschwindet der EF-Fehler. Ich bin mir jedoch nicht sicher, ob das nur den Mist unter den Teppich schaufelt! – Junto

+0

Ein Primärschlüssel muss zwei Anforderungen erfüllen. Erstens muss es einzigartig sein. Zweitens müssen für die Normalisierung alle Nicht-Schlüsselelemente vollständig vom Primärschlüssel abhängig sein. Einige Ihrer zusammengesetzten Schlüssel brechen die Normalisierung ziemlich stark, da es so aussieht, als ob eine Komponente Ihres zusammengesetzten Schlüssels vom anderen Teil des zusammengesetzten Schlüssels abhängt. Es ist ein großes Risiko bei zusammengesetzten Schlüsseln. Also, um Ihre Bedenken zu beantworten, nein, es ist * nicht * nur Mist unter den Teppich schaufeln! –

Antwort

4

Auf einem schnellen Scan von Fehlermeldungen des EF, es mag offensichtlich nicht so, wie Sie Verbindung Tasten sind einrichten, und ich denke, es ist wahrscheinlich Sie in der richtigen Richtung ist stupste. Überlegen Sie nochmals, was Ihre Primärschlüssel einzigartig macht. Ist die Bestell-ID nicht eindeutig, ohne Firmen-ID? Ist eine ProductID nicht eindeutig, ohne eine CompanyID? Eine OrderLine sollte eindeutig ohne CompanyID sein, da eine OrderLine nur mit einer Order verknüpft sein sollte.

Wenn Sie wirklich die CompanyID für all diese benötigen, was wahrscheinlich bedeutet, dass das betreffende Unternehmen Sie mit ProductID und OrderID versorgt, dann möchten Sie möglicherweise eine andere Richtung gehen und Ihre eigenen Primärschlüssel generieren, die nicht sind intrinsisch für die Daten. Richten Sie einfach eine Spalte für die automatische Erhöhung Ihres Primärschlüssels ein und lassen Sie diese die interne Bestell-ID, Bestellnummern-ID, Produkt-ID, Firmen-ID usw. sein. An diesem Punkt benötigt die Bestellungszeile nicht die Bestell-ID oder Firmen-ID des Kunden; der Fremdschlüsselbezug auf den Orden wäre der Ausgangspunkt. (Und die CustomerID sollte nie ein Attribut einer Auftragszeile sein; es ist ein Attribut der Bestellung, nicht die Auftragszeile.)

Compound-Tasten sind einfach chaotisch. Versuchen Sie, das Modell ohne sie zu entwerfen, und sehen Sie, ob es die Dinge vereinfacht.

+0

Ich bin auf die zusammengesetzten Schlüssel einig. Ich bin mir nicht einmal sicher, warum ich sie überhaupt hinzugefügt habe! Late-Night-Programmierung ist nie eine gute Idee für mich. – Junto

+0

Ich werde die Antwort eher auf Cylon Cat als auf EJB geben, hauptsächlich weil er meine Denkprozesse dazu veranlasste, warum ich die zusammengesetzten Schlüssel an erster Stelle hinzugefügt hatte (falsch). Danke euch beiden. – Junto

+0

Ich bin nicht einverstanden. Die Ursache des Fehlers sind die Felder, die Junto nicht verwendet hat, wenn er die Relationen zwischen Tabellen erstellt. Die Firmen-ID in jeder Tabelle hilft sehr bei Multi-Tenant-Sites. –

2

Ich denke, das Speichern der Unternehmensnummer in jeder der Tabellen verletzt Sie mehr als helfen. Ich kann verstehen, warum du das machen willst (als Programmierer/dba kannst du einfach in jede Tabelle gehen und 'sehen', welche Daten denen gehören, die trösten), aber es stört dich bei der Einrichtung der Datenbank wie es sein sollte.

Vermeiden Sie die zusammengesetzten Schlüssel und Ihr Design wird viel einfacher.

+0

Einverstanden. Zusammengesetzte Schlüssel. – Junto

2

Ich denke, dass der Fehler nicht im Design ist. Ist nicht in der EF. Ist in Sql Server Beziehungen.

Lesen Sie die Meldung EF:

Die Beziehung 'FK_Order_Customer' verwendet den Satz von Fremdschlüssel '{CustomerId, CompanyID}', die teilweise in dem Satz von Primärschlüssel ‚enthaltenen { OrderId, CompanyId} 'von die Tabelle' Bestellung '. Der Satz der fremden Schlüssel muss vollständig im Satz der Primärschlüssel oder vollständig nicht enthalten sein, die in der Menge der Primärschlüssel enthalten sind, die einem Modell zugeordnet werden sollen.

ERROR

Actualy die Beziehung betwen Auftrag und Kunden Verwendung nur ein Feld (wahrscheinlich Sie mit der Maus das Feld "CustomerId" von teh Order-Tabelle auf die "Id" des Customer-Tabelle gezogen)

SOLUTION

Rechtsklick auf den Draht, der Auftrags- und Kunden und in der Beziehung auch noch die CompanyID

verbinden

PS: Das Design ist korrekt.

Die CompanyId in jeder Tabelle zu platzieren, ist eine Lösung in der Multi-Tenant-Architektur, da die Skalierbarkeit (in der Regel nur Datensätze aus der Firma loggedIn auswählen) verwendet werden soll.

+0

gibt es keine absolute Wahrheit weder in der Aussage "Keine zusammengesetzten Schlüssel verwenden", noch in "Immer für Multitenancy verwenden". ist abhängig von Datenbank-Zweck und Nutzungsszenario. In DWH-Datenbanken möchte ich zusammengesetzte Schlüssel verwenden. in OLTP würde ich wahrscheinlich noch CompanyID Spalte in jeder Tabelle erstellen, die eine Root-Entität mit einem nicht gruppierten Index darstellt, aber nicht sehen, warum ich es zu einem Teil des Schlüssels machen muss ... und möglicherweise nicht zu Nicht-Root-Entitäten hinzuzufügen wie Bestellzeilen –

0

Wenn Sie unbedingt die Spalte CompanyID zu jeder Tabelle hinzufügen müssen, fügen Sie sie als reguläre Spalte und nicht als zusammengesetzten Schlüssel hinzu. Zusammengesetzte Schlüssel werden meistens verwendet, wenn Sie eine Beziehung von vielen zu vielen implementieren müssen.

Wie erwähnt, erstellen Sie auch einen Non-Clustered-Index auf CompanyID, so dass Joins zur Company-Tabelle von Vorteil sind.

Danke!

0

Erstens: Wie andere sagten, wenn Sie einen Fremdschlüssel referenzieren, verwenden Sie den gesamten Primärschlüssel in der anderen Tabelle (dh beide Felder).

Zweitens kann ich mir nicht vorstellen, eine Spalte CompanyID in den meisten Tabellen in einer ernsthaften Anwendung zu verwenden. OrderDetail könnte vielleicht eine Ausnahme in diesem Fall sein (auch globale Nachschlagetabellen vielleicht, es sei denn, sie sind mandantenabhängig). Das heißt, Sie können keine sichere Art der freien Formsuche in einer Tabelle ausführen, ohne entweder die CompanyID hinzuzufügen oder JOINs bis zu dem Punkt auszuführen, an dem Sie eine Tabelle mit dieser Spalte erreichen. Letzteres kostet natürlich Leistung. Vielleicht könnten Sie in diesem Fall eine Ausnahme für orderdetail machen und nur in der Join-Version suchen (nur zwei Tabellen). Andererseits ist es nicht wirklich konsistent.

Auch in Bezug auf die Herstellung eines Compound-Schlüssels oder nicht: es ist möglich, aber eröffnet die Möglichkeit, dass ein Fehler für die Dauer des Fehlers falsch Informationen (in nicht existent oder andere Personen) schreibt. Versuchen Sie, dies in der Produktion zu beheben, ganz zu schweigen davon, dass es den Kunden erklärt, warum ihre Konkurrenten in ihrem System gesehen werden.

+0

Nachdem ich mit mehreren ORMs herumgespielt habe, bin ich zu dem Schluss gekommen, dass bei Verwendung von Join-Tabellen in n: m-Relationen diese (zumindest größtenteils) von der Mandantenidentität ausgeschlossen werden könnten. ORMs neigen dazu, Probleme damit zu konfrontieren, und tatsächlich wird jede Abfrage, die eine Join-Tabelle betrifft, mindestens eine andere Tabelle enthalten, die eine Tenant-ID enthält. Sehr selten müssten Sie diese selbst abfragen, einfach lösen, indem Sie sie an einen benachbarten Tisch anschließen. – user2921878