线程消息系统数据库模式devise

我试图完成这里解释: 到Facebook和Gmail创build一个线程的私人消息系统 ,但我不完全理解乔尔布朗的答案。 可以请任何人解释。

这是我的数据库表与样本数据的样子(我假设我填写正确的演示目的): 在这里输入图像描述

  1. 我需要显示一个基于LoginId的线程列表(最新的顶部)在LINQ中查询看起来像什么? (我要求的是在一组消息线程中,给我在每个线程中的最新消息) – 就像这是在Facebook上完成的。

  2. 我需要在消息线程(LINQ)中显示所有消息 – >就像在facebook上完成的那样,单击消息,您将看到整个“对话”。

请帮忙! 谢谢

编辑 – >继续乔尔,这是正确的?

在这里输入图像描述

乔尔,我有点困惑,请你解释一下(评论/问题以粗体显示):

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

LoginId 1向LoginId2发送消息=>将新logging插入到MessageThread表中。 另外,MessageThreadParticipantlogging的MessageThreadId = 1,LoginId = 1(发件人)也被插入一条logging。 并且将新logging插入MessageId = 1,MessageThreadid = 1,SenderLoginId = 1(正确??)

这是我在迭代之后所拥有的: 在这里输入图像描述

我觉得我很困惑,因为Loginid 2没有办法知道他有什么信息。 ?? 或者我可能需要插入2条logging到MessageThreadParticipant? (发送者和接收者) – >这种方式都可以看到整个“对话”?

编辑2:乔,我想我可以这样做:

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; 

请纠正我,如果我错了:)

那么你为什么不问问? 🙂

让我试着去定下我对你的要求的理解。 在我看来,你正在看一个线程是两个人之间的消息线性列表(而不是树)。 我想你可能想让更多的人进来,而不仅仅是两个人。 这就像Facebook有人发布消息,然后任何数量的人可以阅读,然后开始添加评论。 当你添加一个评论时,它会把你放到线程中,你开始得到状态更新和电子邮件,告诉你线程中的活动等等。 假设这就是你所追求的,那么我给Big Mikebuild议的模式并不是你正在寻找的。

请考虑以下内容:

架构

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

当用户读取消息时,他们会在MESSAGE_READ_STATE表中获得一个条目,以表明他们已经标记了消息的读取,无论是显式的还是隐式的,具体取决于您的需求。

当有人对线程中的初始消息进行评论时,第二个MESSAGE将与FK一起添加回原始THREAD,并将回复作者(用户)添加到THREAD_PARTICIPANT表中。 因此,消息被一个,两个或更多的参与者添加到线程中。

要在任何线程中获取最新的消息,只需从消息FK到感兴趣的线程的创builddate(或身份密钥)中按MESSAGEsorting降序排列的前1。

要获取用户最近更新的线程,请在消息位于用户为THREAD_PARTICIPANT的线程中的创builddate,按消息顺序降序获取与前1相关的THREAD。

恐怕我不能在LinqPad中声明这些东西。 如果你遇到困难,我可以用表定义和一些SQL来填充答案。 请在评论中提问。

编辑:澄清的要求和实施

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

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

示例数据第1部分示例数据第2部分

编辑#2:访问SQL的线程中的所有消息列表,阅读状态…

使用@OP的模式,这个SQL将得到给定线程中的消息列表,并指示给定用户是否已经读取了每个消息。 消息是最近的第一顺序。

 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; 

请注意,如果公平地称之为读取状态是通过子select来获取的。 这是必要的,因为获取读状态的部分条件需要一个不能满足外连接的where子句。 因此,您可以使用子查询从MessageReadState子表中确定所需的值(可能缺less)。

编辑3:SQL获取所有线程与最新的消息在每个给定的用户…

要获得给定用户参与的所有线程的列表,按照最近的消息先sorting,只显示最近的消息(每个线程有一条消息),那么你可以使用类似的查询,除了不是通过FK将消息过滤到感兴趣的线程,而是通过子查询来过滤消息,该子查询在感兴趣的用户参与的每个线程中查找最新的消息。看起来像这样:

 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; 

根据Joel Brown'answer的说法,您可以将LAST_MESSAGE_ID列添加到THREAD表中,然后让所有使用最后一条消息的线程SQL变得非常简单。 每次发送消息时都必须更新此列。

获取给定用户的每条最新消息

 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