线程消息系统数据库模式设计 [英] thread messaging system database schema design

查看:269
本文介绍了线程消息系统数据库模式设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试完成这里所解释的内容:
不完全符合您的要求。



考虑以下内容:





这里的想法是每次用户启动全新的线程/消息时,它将从THREAD表中的新记录开始。然后将用户添加为THREAD_PARTICIPANT,并将消息的内容添加到指向包含THREAD的MESSAGE。从MESSAGE到USER的FK表示消息的作者。



当用户读取消息时,他们在MESSAGE_READ_STATE表中获取一个条目,表示已经标记了消息读取,明确地或隐含地,取决于你的需求如何。



当有人评论线程中的初始消息时,第二个MESSAGE添加了一个FK返回到原来的THREAD,回复作者(用户)被添加到THREAD_PARTICIPANT表中。因此,消息由一个,两个甚至更多的参与者添加到线程。



要在任何主题中获取最新的消息,只需取得前1从消息FK对于感兴趣的线程的创建日期(或身份密钥)的MESSAGE进行排序。



要获取用户最近更新的线程,从消息在用户是THREAD_PARTICIPANT的线程的创建日期排序降序的消息中获取与顶部1相关的THREAD。



我害怕我在LINQPad中,永远不能把这些东西放在LINQPad中。如果你从上面捕捉到我的漂移,我可以用表定义和一些SQL来解决问题。



编辑:澄清要求和实施



澄清要求:最初我正在考虑公开发布的消息,有机会评论,而Shane是更多的直接消息功能。在这种情况下,初始收件人需要一开始就包含在THREAD_PARTICIPANT表中。



为了一些清楚,让我们在表中放几行。这是场景(为了纪念加拿大日):用户1 DMs用户2询问会议啤酒。用户2回答有关哪里会面和用户1答案的问题。表格看起来像这样(可能是过于简单)






编辑#2:访问SQL以查看线程中所有消息的列表,读取状态...



使用@ OP的架构,这个SQL将得到给定线程中的消息列表,并指出给定的用户是否读取了每条消息。消息是最新的第一个订单。

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

请注意,如果公平地称之为诀窍,那就是读取状态被拾取与子选择。这是必要的,因为获取读取状态的标准的一部分需要不能满足外部连接的where子句。因此,您可以使用子选择从MessageReadState子表中锁定您想要的值(可能缺少)。



编辑3:用于获取所有线程的SQL消息给每个给定的用户...



要获取给定用户参与的所有线程的列表,按最新排序消息首先,只显示最近的消息(每个线程1个消息),然后您将使用与上述相似的查询,除了通过FK将消息过滤到感兴趣的线程之外,您可以通过子查询过滤消息在每个线程中找到感兴趣的用户参与的最新消息。它将如下所示:

  SELECT 
Message.MessageId
,Message.CreateDate
,Message.Body
,Login.Username
,(SELECT MessageReadState.ReadDate
FROM MessageReadState
WHERE MessageReadState .MessageId = Message.MessageId
a nd MessageReadState.LoginId = 2)AS ReadState
FROM Message INNER JOIN登录ON Message.SenderLoginId = Login.LoginId
WHERE(
中的Message.MessageId(SELECT Max(Message.MessageId)
FROM MessageThreadParticipant INNER JOIN消息
ON MessageThreadParticipant.MessageThreadId = Message.MessageThreadId
WHERE MessageThreadParticipant.LoginId = 2
GROUP BY MessageThreadParticipant.MessageThreadId


ORDER BY Message.CreateDate DESC;


I'm trying to achieve exactly what's explained here: Creating a threaded private messaging system like facebook and gmail, however i don't completly understand Joel Brown's answer. can any one please explain.

This is what my db tables look like with sample data (I assume i filled it in correctly for demo purposes):

  1. I need to display a list of threads based on LoginId (newest on top) what would the query look like in LINQ? (what i'm asking is in a a group of message threads, give me the 1 newest message in each thread) - just like this is done on facebook.

  2. I need to display ALL the messages in a message thread (LINQ) -> just like it's done on facebook where you click the message and you would see the whole "conversation" in a tread.

Please help! thanks

EDIT -> continuation Joel, is this correct??

Joel, i'm a bit confused, can you please explain (comments/questions in bold):

The idea here is that every time a user starts a brand new thread/message, it starts with a new record in the THREAD table. The user is then added as a THREAD_PARTICIPANT and the content of the message is added to MESSAGE which points back to the containing THREAD. The FK from MESSAGE to USER indicates the author of the message.

LoginId 1 sends a message to LoginId2 => new record is inserted to MessageThread table. Also a record is inserted to MessageThreadParticipant record with MessageThreadId = 1, LoginId = 1 (the sender). And a new record is inserted into Message table with MessageId =1, MessageThreadid =1, SenderLoginId = 1 (correct??)

this is what i have after that iteration:

I think i'm confused because there is no way for Loginid 2 to know that there is a message for him. ?? OR maybe I need to insert 2 records into MessageThreadParticipant?? (the sender and the receiver)-> this way both can see the whole "conversation"??

EDIT2: Joe, I think I could do this:

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;

Please correct me if i'm wrong :)

解决方案

Well why don't you just ask? :)

Let me try to pin down my understanding of your requirement. It seems to me that you are looking at a thread being a linear list (not a tree) of messages between two people. I would think that you might want to allow more people in than just two. That would be like Facebook insofar as someone posts a message and then any number of people can read it and then start adding comments. When you add a comment it puts you into the thread and you start getting status updates and e-mails telling you about activity in the thread and so forth. Assuming that is what you're after, then the schema I suggested to Big Mike is not exactly what you're looking for.

Consider instead the following:

The idea here is that every time a user starts a brand new thread/message, it starts with a new record in the THREAD table. The user is then added as a THREAD_PARTICIPANT and the content of the message is added to MESSAGE which points back to the containing THREAD. The FK from MESSAGE to USER indicates the author of the message.

When a user reads a message, they get an entry in the MESSAGE_READ_STATE table to indicate that they have marked the message read, either explicitly or implicitly, depending on how your requirements go.

When someone comments on the initial message in the thread, a second MESSAGE is added with an FK back to the original THREAD and the reply author (user) gets added to the THREAD_PARTICIPANT table. And so it goes as messages are added to the thread by one, two or even more participants.

To get the most recent message in any thread, just take the top 1 from MESSAGE sorted descending on create date (or an identity key) where the message FK is to the thread of interest.

To get the most recently updated thread for a user, get the THREAD related to the top 1 from message sorted descending on create date where the message is in a thread in which the user is a THREAD_PARTICIPANT.

I'm afraid I can never state these things in LINQ without breaking out LinqPad. If you are having trouble catching my drift from the above, I could flesh out the answer with table definitions and some SQL. Just ask in the comments.

EDIT: Clarification of Requirements and Implementation

Clarifying the requirements: Initially I was thinking about publicly posted messages with the opportunity for commenting, whereas Shane is after more of the direct message feature. In which case the initial recipient needs to be included in the THREAD_PARTICIPANT table at the outset.

For some clarity, let's put a few rows in tables. Here is the scenario, (in honour of Canada Day): User 1 DMs User 2 to ask about meeting for a beer. User 2 replies with a question about where to meet and User 1 answers. The tables would look something like this: (probably oversimplified)

EDIT #2: Access SQL for list of all messages in a thread, with read state...

Using @OP's schema, this SQL will get a list of messages in a given thread with an indication of whether a given user has read each message or not. Messages are in most recent first order.

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;

Note that the trick, if it's fair to call it that, is that the read state is picked up with a sub-select. This is necessary because part of the criteria for getting the read state requires a where clause that can't be satisfied with an outer join. Therefore you use the subselect to pin down which (possibly missing) value you want from the MessageReadState child table.

EDIT 3: SQL for getting all threads with latest message in each for a given user...

To get a list of all of the threads in which a given user has participated, sorted by most recent message first, with only the most recent message being displayed (1 message per thread) then you would use a similar query to the one above, except instead of filtering messages by their FK to the thread of interest, you filter the messages by a subquery that finds the latest message in each thread that the user of interest participated in. It would look like this:

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;

这篇关于线程消息系统数据库模式设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆