Em um clone StackOverflow, que tipo de relacionamento deve uma tabela de comentários tem que Perguntas e Respostas?

StackOverflow https://stackoverflow.com/questions/987654

Pergunta

Em um aplicativo semelhante à StackOverflow que estou construindo, estou tentando decidir o relacionamento meus Questions, Answers e Comments tabelas devem ter.

Eu poderia ter Questions e Answers tanto ser representado por um único Posts mesa.

Isso permitiria Comments ter uma única chave estrangeira para Posts.

Mas se Questions e Answers são mesas separadas, o que as relações devem Comments tem que cada uma delas?

UPDATE: Embora a resposta escolhida recomenda uma abordagem Classe Table Inheritance e esta parece ser a melhor abordagem em termos de banco de dados, esta opção não é apoiada pelo Rails ORM. Assim, em Rails meus modelos terá que usar Herança de Tabela Única e provavelmente será parecido com este:

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
  );
Foi útil?

Solução

Eu iria com a abordagem Mensagens. Esta é a melhor maneira de garantir a integridade referencial.

Se precisar de colunas adicionais para Perguntas e Respostas, respectivamente, colocá-los em tabelas adicionais com um relacionamento um-para-um com mensagens.

Por exemplo, na sintaxe MySQL:

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;

Isso é chamado de classe Herança de tabelas. Há uma visão agradável de modelar herança com SQL neste artigo: " Inheritance in relacional bancos de dados ".

Pode ser útil usar post_type assim que um determinado posto pode ser apenas uma resposta ou uma pergunta. Você não quer tanto uma resposta e uma pergunta a um referência dada Post. Portanto, este é o propósito da coluna post_type acima. Você pode usar restrições CHECK para fazer cumprir os valores em post_type, ou uso então um gatilho se o seu banco de dados não suporta restrições CHECK.

Eu também fiz uma apresentação que pode ajudá-lo. Os slides são-se em http://www.slideshare.net/billkarwin/sql- antipatterns-atacar. Você deve ler as seções sobre associações polimórficas e do atributo de entidade Value.


Se você usar Herança de Tabela Única, como você disse que você está usando Ruby on Rails, então o DDL SQL ficaria assim:

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; 

Você pode usar uma restrição de chave estrangeira neste exemplo, e eu recomendo que você faz! : -)

Rails filosofia tende a favorecer colocando a aplicação do modelo de dados para a camada de aplicação. Mas sem restrições impor a integridade no no banco de dados, você tem o risco de que erros em seu aplicativo, hoc consultas ou anúncio de uma ferramenta de consulta, pode prejudicar a integridade dos dados.

Outras dicas

Nas redes sociais que eu construir I fazer algo um pouco diferente. Se você pensar sobre isso um comentário poderia ser anexado a praticamente qualquer entidade de um site. Este poderia ser um post, uma discussão no fórum ou post, um artigo, alguém imagem, um perfil de pessoas, um fornecedor de um serviço, etc. Por esta razão eu criar uma tabela SystemObjects que detém o tipo de objeto (referência de tabela). Para a maior parte eu criar registros para as entidades do meu sistema que vai aceitar comentários ... mas estes mapa diretamente para minhas tabelas. Os SystemObjects casas tabela do SystemObjectID, e um nome amigável para referência futura (a tabela de pesquisa).

Com este no lugar Eu, então, criar uma tabela Comentários que tem a referência SystemObjectID para me dizer o mesa para ir olhar em. Então eu também abrigar o SystemObjectRecordID que me diz que PK da tabela referenciada Estou interessado na (juntamente com todos os dados comentário standard).

Eu uso essa noção de tabela de Systemobject para muitos outros conceitos de longo alcance genéricos em meus sites. Pense em Tags, avaliações, comentários, e qualquer outra fruta pendurada que pode ser anexado através de seu site e agregados para uso rápido.

Leia mais sobre isso em meu livro ASP.NET 3.5 Redes Sociais .

Você pode criar uma única tabela comentários com duas chaves estrangeiras, um para questions.questionID e outro para answers.answerId

Você precisaria de duas tabelas de domínio que trazem as relações juntos CommentsForQuestions e CommentsForAnswers. Basicamente, você está indo para necessidade de criar 5 mesas para esta finalidade:

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

O único problema que isso tem é que é inferior à ideia mensagens porque a integridade referencial não é tão forte. Posso garuntee que CommentsForQuestions se conecta a um comentário e uma pergunta, mas não posso evitar tanto uma pergunta e uma resposta de conexão com o mesmo comentário.

A relação de chave estrangeira; você pode ter QuestionComments e AnswerComments, ou você pode ter Comments ter uma coluna de chave estrangeira para ambas as perguntas e respostas (e ter essas colunas ser exclusivo).

Pessoalmente, eu iria com a abordagem mensagens.

Edit: Em consideração, há uma terceira abordagem que o trabalho poder; você pode ter uma tabela de comentários, e depois só tem uma tabela de associação que associa a comentários com tanto uma pergunta ou uma resposta (assim Comentários teria um ID e o comentário, a unir a tabela teria um CommentID, um AnswerID, e uma QuestionID ). Ou, você poderia ter apenas uma mesa comentários, em seguida, ter uma tabela de associação Resposta-Comment, e uma mesa Pergunta-Comment associação separado.

Existem 2 maneiras que eu posso pensar.

Em primeiro lugar, usar outra coluna na tabela de comentário para indicar se o comentário pertence a pergunta ou resposta. Assim, o PK da tabela de comentário torna-se wher PostID é a chave estrangeira para pergunta ou resposta e PostType pode ser someting como 1 = Pergunta e 2 = Resposta.

Em segundo lugar, usar uma tabela de relacionamento para cada pergunta e resposta. Então você tem uma pergunta, resposta, comentário, QuestionComment, e mesa AnswerComment.

Vamos dizer que a chave primária da pergunta, resposta, mesas de comentário estão QuestionID, AnswerID e CommentID respectivamente. Em seguida, as colunas de QuestionComment seria [QuestionID, CommentID]. Da mesma forma, as colunas de AnswerComment seria [AnswerID, CommentID].

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top