Frage

Hier ist meine Datenbankstruktur:

database schema

In meiner App habe ich eine Firmenverwaltung von Kunden, Mitarbeitern und Filialen.

Kunden und Mitarbeiter sind einer Person, einer Einzelperson und einem Benutzer zugeordnet.Zweigstellen sind einer Person und einem Unternehmen zugeordnet.

Um also einen neuen Kunden oder Mitarbeiter einzufügen, muss ich zunächst dessen gemeinsame Daten eingeben Person Tabelle, seine Personendaten in Person Tabelle, dann seine Benutzerdaten in User Tabelle und erstellen Sie schließlich einen neuen Datensatz Customer oder Employee Tisch.

Um einen neuen Zweig einzufügen, muss ich zuerst seine allgemeinen Daten einfügen Person Tabelle, dann seine Unternehmensdaten in Company Tabelle und erstellen Sie schließlich einen neuen Datensatz Branch Tisch.

Ich bin neu im MVC-Konzept und weiß nicht genau, wie ich meine Modellklassen so gestalten soll, dass sie CRUD sind.Ich verwende das CodeIgniter-Framework, aber ich denke, es ist hier irrelevant.Soll ich für jede Datenbanktabelle ein eigenes Klassenmodell erstellen?Wenn ja, wie soll ich das codieren?(nur Theorie)

Um beispielsweise einen neuen Kunden einzufügen...

  1. Starten Sie eine neue Transaktion
  2. Instanziieren Sie eine neue Person
  3. Geben Sie die Daten der Person ein
  4. Person speichern
  5. Instanziieren Sie eine neue Person
  6. Füllen Sie die Daten der Person aus und beziehen Sie sie auf ihre Person
  7. Einzelperson speichern
  8. Instanziieren Sie einen neuen Benutzer
  9. Füllen Sie die Daten des Benutzers aus und beziehen Sie ihn auf seine Person
  10. Benutzer speichern
  11. Instanziieren Sie einen neuen Kunden
  12. Füllen Sie die Daten des Kunden aus und beziehen Sie ihn auf seine Person
  13. Kunde speichern
  14. Transaktion beenden

Ist das korrekt?Wo sollte dieser Code im Controller des Kunden sein?Gibt es eine bessere Konvention zur Verwendung dieser Datenbankstruktur (ich muss das dritte Normalformdesign verwenden)?

War es hilfreich?

Lösung

Ok, interessant, warum willst du 3NF verwenden?

In MVC-Webframeworks (wie Codeigniter, Zend Framework oder Ruby on Rails) benötigen Sie kein 3NF und kümmern sich nicht einmal um die verschiedenen Tabellen.Was Sie versuchen, würde ich sagen, ist die Vererbung mehrerer Tabellen, was nicht sehr verbreitet ist.

Eigentlich haben Sie also, sagen wir, Custumer Klasse, die alle Attribute Ihrer Kunden-, Benutzer- und Personentabelle enthält.Um bei MVC und dem zu bleiben dünner Controller Ansatz, Sie hätten eine save Aktion in Ihrem CustomerController Klasse, die diese Attribute akzeptiert und daraus ein Objekt instanziiert Costumer Klasse:

class CostumerController {
    function create() {
        Costumer c = new Customer();
        c.save($_POST['costumer']);
    }
}

(Stellen Sie sicher, dass Sie die Parameter für SQL-Injections überprüfen, aber Ihr Framework sollte das irgendwie bewältigen.)

Ihre benutzerdefinierte Klasse sollte über einen Konstruktor verfügen, der alle seine Attribute akzeptiert und in den entsprechenden Tabellen speichert.D.h.:

class Costumer {
    function save(params) {
        $sql = 'INSERT INTO person SET `phoneNumber` = "' . params['phonenumber'] . '"';
        $dbh->query($sql);
        $lastid = PDO::lastInsertId;
        $sql = 'INSERT INTO user SET `password` = "'. md5(params['password']) . '", `personId` = "' . $lastid . '";
        ...
    }
}

Wie Sie vielleicht bemerkt haben, habe ich die SQL-Anweisungen und einen Teil des Codes gekürzt, da ich CodeIgniter nicht kenne.Die Idee besteht jedoch darin, alle benötigten Daten der Speichermethode zu übergeben, die sie in den entsprechenden Tabellen in Ihrer Datenbank speichert.Erinnern: Nur die Modellklasse kommuniziert mit der Datenbank in MVC.

Das Problem ist die ID, die Sie in anderen Tabellen als Fremdschlüssel verwenden.Nachdem Sie Ihre Daten in eine Person eingegeben haben, müssen Sie die Tabelle nach der gerade eingefügten ID abfragen und diese in einer anderen Tabelle verwenden.

Aus diesem Grund gibt es einige Frameworks (sozusagen: alles, was ich weiß), verwenden Sie standardmäßig die Vererbung einer einzelnen Tabelle.Stellen Sie es sich so vor:

So wie du es beschrieben hast, dein Costumer erbt von User was erbt von Person.Alle diese Tabellen werden zu einer Tabelle zusammengeführt, die auch eine enthält type Attribut, das angibt, welchen Typ das Objekt dieser Zeile hat, in unserem Fall: Customer, User oder Person.Wenn Sie nur einen Benutzer hinzufügen, werden alle nicht verwendeten Attribute auf gesetzt NULL.Aber das würde natürlich Ihre 3NF zerstören.

Was ich jedoch nicht verstehe, ist, warum man immer 1:1-Beziehungen benötigt.Zum Beispiel zwischen Person Und Company.Oh, jetzt verstehe ich es, denn es gibt keine companyId (FK) In Person, viele Persons können in einem sein Company.Aber warum Branchhabe einen personId (FK).Normalerweise arbeiten mehr Personen in einer Filiale, nicht wahr?

Zurück zu Ihrer Frage

Sie können entweder verwenden Thin-Controller-Fat-Modell oder Fat-Controller-Thin-Modell, obwohl ich das erste bevorzuge.In diesem Fall hätten Sie nur ein paar Zeilen in Ihrem Controller und mehr Logik in Ihrem Modell (wie in meinem Beispiel oben).Die Kommunikation mit der Datenbank erfolgt nur in Ihren Modellklassen.Normalerweise verfolgen Sie nicht den Ansatz „Eine Tabelle entspricht einem Modelltyp“, es kann aber auch sein, dass mehr als ein Modelltyp auf eine Tabelle zugreift (siehe die Sache mit der Vererbung einzelner Tabellen).

Ein anderer Ansatz

Du könntest eine haben CostumerModell, das Ihre Daten akzeptiert und sie so „gruppiert“, wie Ihre Tabellen „verstreut“ sind:

class Customer {
    function save(params) {
        Person $person = new Person();
        $person.save(params['person']);
        User $user = new User();
        $user.save(params['user'], $person->id);
        ....
    }
}

Aber...Nun, wie gesagt, ich würde vorschlagen, dass Sie den 3NF-Ansatz verlassen und STI (Single Table Inheritance) verwenden.

Vergiss es nicht Achten Sie darauf, Formulardaten in Anführungszeichen zu setzen, um SQL-Injections zu vermeiden, oder prüfen Sie, welche Funktionen Ihr Framework bietet, um dies für Sie zu erledigen.

Entschuldigung für etwaige Fehler im Code, ich habe nur aus dem Gedächtnis „codiert“ und ihn nicht einmal syntaktisch analysiert.

HTH

Andere Tipps

TL;DR.NEIN.Sie sollten nicht für jede Tabelle ein separates Modell erstellen.


Erstens ist Ihr DB-Diagramm falsch.Die Fragmentierung von User, Individual Und Person.Sie haben alle 1:1-Beziehungen und das User Die Tabelle scheint äußerst überflüssig zu sein. Oh ..und was ist mit der singulären Namenskonvention für Tabellen?!

Ohnehin ..


Tatsächlich handelt es sich bei dem, was Sie als „Modelle“ bezeichnen, tatsächlich um etwas Domänenobjekte.Sie sind nur ein Teil der Modellebene.Und ja, das Modell in MVC ist eine Ebene.Weder eine Klasse noch ein Objekt.

Bei ordnungsgemäßer Implementierung wären Ihre Domänenobjekte von Klassen getrennt, die Speicherlogik implementieren (normalerweise: Datenmapper ).Abgesehen davon, dass man sich daran hält SRP Eine solche Implementierung würde Ihnen auch die Möglichkeit geben, dass das Domänenobjekt von der Speicherform unabhängig ist.Im Gegensatz dazu kann ein Data Mapper mehrere Tabellen einem einzelnen Domänenobjekt zuordnen Aktiver Rekord (Anti-)Muster, das die Logik mit Speichermechanismen in einen Topf wirft.

Was die Controller betrifft ...Also.Sie sollten für jede Ansicht einen einzigen Controller haben.Controller sollen lediglich den Status der Modellebene und der aktuellen Ansicht ändern, indem sie Daten aus eingehenden Anforderungen weitergeben.

Ihre Frage scheint darauf hinzudeuten, dass die Domänengeschäftslogik von der Modellebene in die Präsentationsebene gelangt.Stattdessen sollten Sie Dienste erstellen (Sie können sie sich als „Domänenobjekte höherer Ordnung“ vorstellen), die die Interaktion zwischen mehreren Domänenobjekten und den von Ihnen gewählten Speicherabstraktionen (Datenzuordnungen, DAOs, Repositorys, Arbeitseinheiten usw.) erleichtern.usw).Der Controller sollte nur den Benutzerverwaltungsdienst: „Hier sind Daten, erstelle mir ein neues Benutzerkonto.“


P.S. : Sie könnten finden dieser Beitrag relevant.

Sie werden wahrscheinlich viele unterschiedliche Meinungen bekommen.Ohne allzu viele Details über Ihre Bewerbung zu kennen, wäre eine der möglichen Vorgehensweisen, diese in Anwendungsdienste zu integrieren.

Dann verwendet Ihre Web-App den richtigen App-Dienst, um diese Logik auszuführen.Dadurch wird Ihr Webinterface von der Anwendungslogik entkoppelt und somit eine andere Anwendung (z. B.(z. B. ein interner Revisionsdienst), um dieselbe Logik zu verwenden, ohne die Implementierungslogik zu duplizieren.

Da ich PHP nicht kenne, verwende ich Pseudocode im .NET-Stil, ohne dabei eine bestimmte Technologie im Hinterkopf zu haben (deshalb werden Methodenaufrufe bewusst nicht für gängige Web-App-Frameworks durchgeführt).

class CustomerService // typically it will be an interface ICustomerSvc, but nevermind...
{ 
   // this will implement your logic to add customer - points 1-14
   // it might return the ID of the customer or not (CustomerID is typically
   // an integer, string, GUID, etc
   CustomerID AddCustomer(CustomerInfo info); 
}

Dann verfügen Sie in Ihrer Web-App über eine Methode, die die Webanfrage verarbeitet

void AddCustomer(CustomerData data) 
{
   // note: data is not necessarily the same CustomerInfo type.
   // this is your web app model, and can be same but doesn't have to
   try {
      // m_customerSvc - can be instantiated withing class, provided in constructor, etc
      var id = m_customerSvc.AddCustomer(data);      // add a customer
      RedirectTo("confirmation_page_for_user_", id); // show confirmation page
   }
   catch(...) {
      RedirectTo("error_page");
   }
}

Eine Sache, die nicht wirklich offensichtlich ist, ist, wo die Transaktionsabwicklung erfolgen soll.Es kann sich innerhalb des Anwendungsdiensts oder innerhalb der Web-Request-Handler-Methode befinden.

Obwohl ersteres intuitiver zu sein scheint, besteht das Problem darin, dass App-Dienste häufig nicht genügend Kontext kennen, um über die Transaktionsabwicklung zu entscheiden.Stellen Sie sich dieses beliebte Beispiel für eine Geldüberweisung vor:

 m_svc.TakeMoney(account1, amount);
 m_svc.AddMoney(account2, amount);

Der Dienst kann keine Transaktionen innerhalb der Dienstmethodenaufrufe verarbeiten, denn wenn die erste Methode erfolgreich ist und die zweite fehlschlägt, kommt es zu einem inkonsistenten Status, bei dem Geld von einem Konto abgebucht wurde, aber nie auf dem anderen Konto ankam.

Daher muss die Transaktion extern verwaltet werden:

using(var tx = new Transaction())
{
   // now both execute within same transaction
   m_svc.TakeMoney(account1, amount);
   m_svc.AddMoney(account2, amount);
}

Es liegt an Ihnen, zu entscheiden, was am besten zu Ihrer App passt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top