web-dev-qa-db-fra.com

conception du schéma de la base de données du système de messagerie des threads

J'essaie de réaliser exactement ce qui est expliqué ici: Création d'un système de messagerie privé fileté comme Facebook et Gmail , mais je ne comprends pas complètement la réponse de Joel Brown. quelqu'un peut-il expliquer.

Voici à quoi ressemblent mes tables db avec des exemples de données (je suppose que je les ai remplies correctement à des fins de démonstration): enter image description here

  1. J'ai besoin d'afficher une liste de threads basés sur LoginId (le plus récent en haut) à quoi ressemblerait la requête dans LINQ? (ce que je demande est dans un groupe de fils de messages, donnez-moi le 1 message le plus récent dans chaque fil) - tout comme cela se fait sur Facebook.

  2. Je dois afficher TOUS les messages dans un fil de messages (LINQ) -> tout comme cela se fait sur Facebook où vous cliquez sur le message et vous verriez toute la "conversation" dans une bande de roulement.

Aidez-moi! Merci

[~ # ~] modifier [~ # ~] -> suite Joel, est-ce correct ??

enter image description here

Joel, je suis un peu confus, pouvez-vous s'il vous plaît expliquer (commentaires/questions en gras):

L'idée ici est que chaque fois qu'un utilisateur démarre un nouveau fil/message, il commence par un nouvel enregistrement dans la table THREAD. L'utilisateur est ensuite ajouté en tant que THREAD_PARTICIPANT et le contenu du message est ajouté à MESSAGE qui pointe vers le THREAD contenant. Le FK de MESSAGE à USER indique l'auteur du message.

LoginId 1 envoie un message à LoginId2 => un nouvel enregistrement est inséré dans la table MessageThread. Un enregistrement est également inséré dans l'enregistrement MessageThreadParticipant avec MessageThreadId = 1, LoginId = 1 (l'expéditeur). Et un nouvel enregistrement est inséré dans la table Message avec MessageId = 1, MessageThreadid = 1, SenderLoginId = 1 (correct ??)

voici ce que j'ai après cette itération: enter image description here

Je pense que je suis confus car il n'y a aucun moyen pour Loginid 2 de savoir qu'il y a un message pour lui. ?? OR peut-être que je dois insérer 2 enregistrements dans MessageThreadParticipant ?? (l'expéditeur et le destinataire) -> de cette façon, les deux peuvent voir toute la "conversation" ??

EDIT2: Joe, je pense que je pourrais faire ceci:

SELECT
  Message.MessageId, Message.CreateDate, Message.Body, Login.Username, Message.SenderLoginId
, (SELECT MessageReadState.ReadDate 
   FROM MessageReadState 
   WHERE MessageReadState.MessageId = Message.MessageId 
     ) as ReadDate
FROM Message 
    INNER JOIN Login ON Message.SenderLoginId = Login.LoginId
    INNER JOIN MessageThreadParticipant mtp on mtp.MessageThreadId = Message.MessageThreadId 
AND ( Message.MessageId in 
        ( SELECT Max(Message.MessageId)
          FROM MessageThreadParticipant INNER JOIN Message 
            ON MessageThreadParticipant.MessageThreadId = Message.MessageThreadId
          GROUP BY MessageThreadParticipant.MessageThreadId
        )
      )
Where mtp.LoginId = 2
ORDER BY Message.CreateDate DESC;

Corrigez-moi si j'ai tort, s'il-vous plait :)

40
ShaneKm

Eh bien, pourquoi ne demandez-vous pas simplement? :)

Permettez-moi d'essayer de préciser ma compréhension de vos besoins. Il me semble que vous regardez un fil qui est une liste linéaire (pas un arbre) de messages entre deux personnes. Je pense que vous voudrez peut-être autoriser plus de personnes que deux. Ce serait comme Facebook dans la mesure où quelqu'un poste un message, puis n'importe quel nombre de personnes peuvent le lire et commencer à ajouter des commentaires. Lorsque vous ajoutez un commentaire, il vous place dans le fil de discussion et vous commencez à recevoir des mises à jour de statut et des e-mails vous informant de l'activité dans le fil de discussion, etc. En supposant que c'est ce que vous recherchez, le schéma que j'ai suggéré Big Mike n'est pas exactement ce que vous recherchez.

Considérez plutôt ce qui suit:

Schema

L'idée ici est que chaque fois qu'un utilisateur démarre un nouveau fil/message, il commence par un nouvel enregistrement dans la table THREAD. L'utilisateur est ensuite ajouté en tant que THREAD_PARTICIPANT et le contenu du message est ajouté à MESSAGE qui pointe vers le THREAD contenant. Le FK de MESSAGE à USER indique l'auteur du message.

Lorsqu'un utilisateur lit un message, il obtient une entrée dans la table MESSAGE_READ_STATE pour indiquer qu'il a marqué le message comme lu, explicitement ou implicitement, en fonction de la manière dont vos besoins se présentent.

Lorsque quelqu'un commente le message initial dans le fil, un deuxième MESSAGE est ajouté avec un FK au THREAD d'origine et l'auteur de la réponse (utilisateur) est ajouté à la table THREAD_PARTICIPANT. Et il en va de même lorsque les messages sont ajoutés au fil par un, deux ou même plusieurs participants.

Pour obtenir le message le plus récent dans n'importe quel fil, il suffit de prendre le top 1 du MESSAGE trié par ordre décroissant à la date de création (ou une clé d'identité) où le message FK est vers le fil d'intérêt.

Pour obtenir le fil de discussion le plus récemment mis à jour pour un utilisateur, obtenez le THREAD associé au premier 1 du message trié par ordre décroissant à la date de création du message dans un fil de discussion dans lequel l'utilisateur est un THREAD_PARTICIPANT.

J'ai peur de ne jamais pouvoir déclarer ces choses dans LINQ sans sortir LinqPad. Si vous avez du mal à comprendre ma dérive de ce qui précède, je pourrais étoffer la réponse avec des définitions de table et un peu de SQL. Il suffit de demander dans les commentaires.

EDIT: Clarification des exigences et mise en œuvre

Clarifier les exigences: au départ, je pensais aux messages publiés publiquement avec la possibilité de commenter, tandis que Shane est après plus de la fonction de message direct. Dans ce cas, le destinataire initial doit être inclus dans la table THREAD_PARTICIPANT dès le départ.

Pour plus de clarté, mettons quelques lignes dans les tableaux. Voici le scénario, (en l'honneur de la fête du Canada): Utilisateur 1 DMs Utilisateur 2 pour demander une réunion pour une bière. L'utilisateur 2 répond par une question sur le lieu de rencontre et les réponses de l'utilisateur 1. Les tableaux ressembleraient à ceci: (probablement trop simplifiés)

Sample Data Part 1Sample Data Part 2

EDIT # 2: Accédez à SQL pour la liste de tous les messages dans un thread, avec l'état de lecture ...

En utilisant le schéma de @ OP, ce SQL obtiendra une liste de messages dans un thread donné avec une indication si un utilisateur donné a lu chaque message ou non. Les messages sont dans le premier ordre le plus récent.

SELECT 
  Message.MessageId
, Message.CreateDate
, Message.Body
, Login.Username
, (SELECT MessageReadState.ReadDate 
   FROM MessageReadState 
   WHERE MessageReadState.MessageId = Message.MessageId 
     and MessageReadState.LoginId = 2) as ReadState
FROM (Message INNER JOIN Login ON Message.SenderLoginId = Login.LoginId) 
WHERE (((Message.MessageThreadId)=10))
ORDER BY Message.CreateDate DESC;

Notez que l'astuce, s'il est juste de l'appeler ainsi, est que l'état de lecture est détecté avec une sous-sélection. Cela est nécessaire car une partie des critères d'obtention de l'état de lecture nécessite une clause where qui ne peut pas être satisfaite avec une jointure externe. Par conséquent, vous utilisez la sous-sélection pour identifier la valeur (éventuellement manquante) que vous souhaitez dans la table enfant MessageReadState.

EDIT 3: SQL pour obtenir tous les threads avec le dernier message dans chacun pour un utilisateur donné ...

Pour obtenir une liste de toutes les discussions auxquelles un utilisateur donné a participé, triées d'abord par le message le plus récent, avec uniquement le message le plus récent affiché (1 message par thread), vous devez alors utiliser une requête similaire à celle ci-dessus, sauf qu'au lieu de filtrer les messages par leur FK vers le thread d'intérêt, vous filtrez les messages par une sous-requête qui trouve le dernier message dans chaque thread auquel l'utilisateur d'intérêt a participé. Cela ressemblerait à ceci:

SELECT
  Message.MessageId
, Message.CreateDate
, Message.Body
, Login.Username
, (SELECT MessageReadState.ReadDate 
   FROM MessageReadState 
   WHERE MessageReadState.MessageId = Message.MessageId 
     and MessageReadState.LoginId = 2) AS ReadState
FROM Message INNER JOIN Login ON Message.SenderLoginId = Login.LoginId
WHERE ( Message.MessageId in 
        ( SELECT Max(Message.MessageId)
          FROM MessageThreadParticipant INNER JOIN Message 
            ON MessageThreadParticipant.MessageThreadId = Message.MessageThreadId
          WHERE MessageThreadParticipant.LoginId=2
          GROUP BY MessageThreadParticipant.MessageThreadId
        )
      )
ORDER BY Message.CreateDate DESC;
77
Joel Brown

Selon Joel Brown'answer, vous pouvez ajouter LAST_MESSAGE_ID colonne dans la table THREAD puis obtenir tous les threads avec les derniers messages SQL est devenu très simple. Vous devez mettre à jour cette colonne lorsque chaque message est envoyé.

Obtenir toutes les discussions avec le dernier message dans chacune pour un utilisateur donné

SELECT *
FROM THREAD T
INNER JOIN MESSAGE M ON T.LAST_MESSAGE_ID=M.MESSAGE_ID
INNER JOIN USER SENDER ON M.USER_ID=SENDER.USER_ID
LEFT JOIN MessageReadState MRS ON M.MESSAGE_ID=MRS.MESSAGE_ID AND MRS.USER_ID=2
2
Alexander