12 Stimmen

In einem StackOverflow-Klon, welche Beziehung sollte eine Kommentare-Tabelle zu Fragen und Antworten haben?

In einer Anwendung, die StackOverflow ähnelt und die ich gerade aufbaue, versuche ich zu entscheiden, welche Beziehung meine Questions , Answers y Comments Tabellen haben sollten.

Ich könnte Questions y Answers beide durch eine einzige Tabelle dargestellt werden Posts .

Dies würde es ermöglichen Comments mit einem einzigen Fremdschlüssel zu Posts .

Aber wenn Questions y Answers getrennte Tabellen sind, welche Beziehungen sollten Comments zu jedem dieser Punkte haben?

UPDATE: Obwohl die gewählte Antwort einen Class Table Inheritance-Ansatz empfiehlt und dies aus Sicht der Datenbank der beste Ansatz zu sein scheint, wird diese Option vom Rails ORM nicht unterstützt. In Rails müssen meine Modelle also Single Table Inheritance verwenden und werden wahrscheinlich wie folgt aussehen:

class Post < ActiveRecord::Base  
end  

class Question < Post  
  has_many :answers, :foreign_key => :parent_id  
  has_many :comments, :foreign_key => :parent_id  
end  

class Answer < Post  
  belongs_to :question, :foreign_key => :parent_id  
  has_many :comments, :foreign_key => :parent_id  
end  

class Comment < Post  
  belongs_to :question, :foreign_key => :parent_id  
  belongs_to :answer, :foreign_key => :parent_id  
end

class CreatePosts < ActiveRecord::Migration  
    def self.up  
      create_table :posts do |t|  
        t.string :type 
        t.string :author   
        t.text :content  
        t.integer :parent_id   
        t.timestamps  
      end  
    end  

    def self.down  
      drop_table :posts  
    end  
end

CREATE TABLE "posts" (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,  
  "type" varchar(255),  
  "author" varchar(255),  
  "content" text,  
  "parent_id" integer,  
  "created_at" datetime, 
  "updated_at" datetime
  );

17voto

Bill Karwin Punkte 493880

Ich würde mich für den Ansatz der Post entscheiden. Dies ist der beste Weg, um die referenzielle Integrität zu gewährleisten.

Wenn Sie zusätzliche Spalten für Antworten bzw. Fragen benötigen, legen Sie diese in zusätzliche Tabellen mit einer Eins-zu-Eins-Beziehung zu den Beiträgen an.

Zum Beispiel in der MySQL-Syntax:

CREATE TABLE Posts (
  post_id     SERIAL PRIMARY KEY,
  post_type   CHAR(1),              -- must be 'Q' or 'A'
  -- other columns common to both types of Post
  UNIQUE KEY (post_id, post_type) -- to support foreign keys
) ENGINE=InnoDB;

CREATE TABLE Comments (
  comment_id  SERIAL PRIMARY KEY, 
  post_id     BIGINT UNSIGNED NOT NULL,
  -- other columns for comments (e.g. date, who, text)
  FOREIGN KEY (post_id) REFERENCES Posts(post_id)
) ENGINE=InnoDB; 

CREATE TABLE Questions (
  post_id     BIGINT UNSIGNED PRIMARY KEY,
  post_type   CHAR(1),              -- must be 'Q'
  -- other columns specific to Questions
  FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
) ENGINE=InnoDB;

CREATE TABLE Answers (
  post_id     BIGINT UNSIGNED PRIMARY KEY,
  post_type   CHAR(1),              -- must be 'A'
  question_id BIGINT UNSIGNED NOT NULL,
  -- other columns specific to Answers
  FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
  FOREIGN KEY (question_id) REFERENCES Questions(post_id)
) ENGINE=InnoDB;

Dies wird als Klassentabellenvererbung bezeichnet. Einen guten Überblick über die Modellierung der Vererbung mit SQL gibt dieser Artikel: " Vererbung in relationalen Datenbanken ."

Es kann hilfreich sein, post_type zu verwenden, damit ein bestimmter Beitrag nur aus einer Antwort oder einer Frage bestehen kann. Sie wollen nicht, dass sowohl eine Antwort als auch eine Frage auf einen bestimmten Beitrag verweisen. Dies ist also der Zweck der post_type Spalte oben. Sie können CHECK-Beschränkungen verwenden, um die Werte in post_type oder verwenden Sie einen Trigger, wenn Ihre Datenbank keine CHECK-Constraints unterstützt.

Ich habe auch eine Präsentation erstellt, die Ihnen helfen könnte. Die Folien sind zu finden unter http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back . Sie sollten die Abschnitte über polymorphe Assoziationen und Entity-Attribute-Value lesen.


Wenn Sie Single Table Inheritance verwenden, da Sie sagten, Sie verwenden Ruby on Rails, dann würde die SQL DDL wie folgt aussehen:

CREATE TABLE Posts (
  post_id     SERIAL PRIMARY KEY,
  post_type   CHAR(1),              -- must be 'Q' or 'A'
  -- other columns for both types of Post
  -- Question-specific columns are NULL for Answers, and vice versa.
) ENGINE=InnoDB;

CREATE TABLE Comments (
  comment_id  SERIAL PRIMARY KEY, 
  post_id     BIGINT UNSIGNED NOT NULL,
  -- other columns for comments (e.g. date, who, text)
  FOREIGN KEY (post_id) REFERENCES Posts(post_id)
) ENGINE=InnoDB; 

Sie können in diesem Beispiel eine Fremdschlüssel-Beschränkung verwenden, und ich empfehle Ihnen, dies zu tun! :-)

Die Rails-Philosophie neigt dazu, die Durchsetzung des Datenmodells in die Anwendungsschicht zu verlagern. Aber ohne Constraints, die die Integrität in der Datenbank erzwingen, besteht das Risiko, dass Bugs in der Anwendung oder Ad-hoc-Abfragen eines Abfragetools die Datenintegrität beeinträchtigen können.

4voto

Andrew Siemer Punkte 10110

Bei den sozialen Netzwerken, die ich aufbaue, gehe ich etwas anders vor. Wenn man darüber nachdenkt, kann ein Kommentar an jede beliebige Entität auf einer Website angehängt werden. Das kann ein Blogbeitrag, ein Forumsthread oder -beitrag, ein Artikel, ein Bild einer Person, ein Personenprofil, ein Anbieter einer Dienstleistung usw. sein. Aus diesem Grund erstelle ich eine SystemObjects-Tabelle, die den Objekttyp enthält (Tabellenreferenz). In den meisten Fällen erstelle ich Datensätze für die Entitäten meines Systems, die Kommentare akzeptieren... aber diese werden direkt meinen Tabellen zugeordnet. Die SystemObjects-Tabelle enthält die SystemObjectID und einen freundlichen Namen für zukünftige Referenzen (eine Nachschlagetabelle).

Dann erstelle ich eine Tabelle Comments, die den SystemObjectID-Verweis enthält, um mir zu sagen, in welcher Tabelle ich suchen muss. Dann beherberge ich auch die SystemObjectRecordID, die mir sagt, an welcher PK der referenzierten Tabelle ich interessiert bin (zusammen mit allen Standard-Kommentardaten).

Ich verwende diesen Begriff der SystemObject-Tabelle für viele andere generische, weitreichende Konzepte in meinen Sites. Denken Sie an Tags, Bewertungen, Kommentare und alle anderen Dinge, die auf Ihrer Website angehängt und zur schnellen Verwendung zusammengefasst werden können.

Lesen Sie mehr darüber in meinem Buch ASP.NET 3.5 Soziale Netzwerke .

2voto

Nathan Koop Punkte 23863

Sie könnten eine einzige Kommentartabelle mit zwei Fremdschlüsseln erstellen, einen zu questions.questionID und den anderen zu answers.answerId

1voto

Orion Adrian Punkte 18345

Sie benötigen zwei Domänentabellen, die die Beziehungen zwischen CommentsForQuestions und CommentsForAnswers zusammenführen. Im Grunde müssen Sie zu diesem Zweck 5 Tabellen erstellen:

Questions
Answers
Comments
CommentsForQuestions (relates comments to questions)
CommentsForAnswers (relates comments to answers)

Das einzige Problem dabei ist, dass es der Idee mit den Pfosten unterlegen ist, weil die referenzielle Integrität nicht so stark ist. Ich kann garantieren, dass CommentsForQuestions mit einem Kommentar und einer Frage verbunden ist, aber ich kann nicht verhindern, dass sowohl eine Frage als auch eine Antwort mit demselben Kommentar verbunden sind.

1voto

Paul Sonier Punkte 37609

Eine Fremdschlüsselbeziehung; Sie können entweder QuestionComments und AnswerComments haben, oder Sie können Comments eine Fremdschlüsselspalte sowohl für Fragen als auch für Antworten haben (und diese Spalten exklusiv sein lassen).

Ich persönlich würde mich für den Ansatz der Post entscheiden.

Edit: Wenn man darüber nachdenkt, gibt es noch einen dritten Ansatz, der funktionieren könnte; man könnte eine Tabelle Kommentare haben und dann nur eine Assoziationstabelle, die die Kommentare entweder mit einer Frage oder einer Antwort verknüpft (also hätten die Kommentare eine ID und den Kommentar, die Assoziationstabelle hätte eine CommentID, eine AnswerID und eine QuestionID). Oder Sie könnten nur eine Tabelle "Kommentare" haben, dann eine Zuordnungstabelle "Antwort-Kommentar" und eine separate Zuordnungstabelle "Frage-Kommentar".

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X