asp.net - 线程消息系统数据库架构设计

标签 asp.net database linq entity-framework database-design

我正在努力实现这里所解释的内容:
Creating a threaded private messaging system like facebook and gmail ,
但是我不完全理解乔尔布朗的回答。任何人都可以请解释一下。

这是我的数据库表与示例数据的样子(我假设我为了演示目的正确填写了它):
enter image description here

  • 我需要显示基于 LoginId 的线程列表(最新的在顶部) LINQ 中的查询是什么样的? (我要问的是在一组消息线程中,在每个线程中给我一条最新消息)-就像在 facebook 上完成的一样。
  • 我需要在消息线程 (LINQ) 中显示所有消息 -> 就像在 Facebook 上完成的那样,您单击消息,您会看到整个“对话”。

  • 请帮忙!
    谢谢

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

    enter image description here

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

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

    LoginId 1 向 LoginId2 发送消息 => 新记录插入到 MessageThread 表中。还将一条记录插入到 MessageThreadParticipant 记录,其中 MessageThreadId = 1,LoginId = 1(发件人)。并在 Message 表中插入一条新记录,MessageId =1,MessageThreadid =1,SenderLoginId = 1(正确??)

    这就是我在迭代之后的内容:
    enter image description here

    我想我很困惑,因为 Loginid 2 无法知道有给他的消息。 ??或者我可能需要在 MessageThreadParticipant 中插入 2 条记录? (发送方和接收方)-> 这样双方都可以看到整个“对话”??

    编辑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 Mike不完全是你要找的。

    请考虑以下情况:

    Schema

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

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

    当有人对线程中的初始消息发表评论时,第二个 MESSAGE 会添加一个 FK 回到原始 THREAD,并且回复作者(用户)被添加到 THREAD_PARTICIPANT 表中。当消息由一个、两个甚至更多参与者添加到线程时,情况也是如此。

    要获取任何线程中的最新消息,只需从 MESSAGE 中获取按创建日期(或身份 key )降序排序的前 1 条消息,其中消息 FK 发送到感兴趣的线程。

    要获取用户最近更新的线程,请从按创建日期降序排序的消息中获取与前 1 项相关的线程,其中消息位于用户是 THREAD_PARTICIPANT 的线程中。

    恐怕我永远无法在不打破 LinqPad 的情况下在 LINQ 中陈述这些事情。如果您无法理解上述内容,我可以用表定义和一些 SQL 来充实答案。只需在评论中提问。

    编辑:要求和实现的澄清

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

    为了清楚起见,让我们在表格中放置几行。这是场景,(为了纪念加拿大日):用户 1 向用户 2 发送 DM,询问 session 是否喝啤酒。用户 2 回答关于在哪里见面的问题,用户 1 回答。表格看起来像这样:(可能过于简化)

    Sample Data Part 1
    Sample Data Part 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;
    

    请注意,如果可以公平地称呼它,技巧是通过子选择获取读取状态。这是必要的,因为获取读取状态的部分标准需要外连接无法满足的 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 
         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;
    

    关于asp.net - 线程消息系统数据库架构设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6541302/

    相关文章:

    c# - 在LINQ查询中,调用ToDictionary时,为键和值分配了什么?

    c# - 使用LINQ查询多个表,将结果抓取到字典

    asp.net - 通用 SQL 参数在 ASP.NET 中的 MySQL 连接器的 SqlDataSource 中不起作用

    java se 与 hibernate 和 JavaDB。我如何部署应用程序?

    database - Netezza 性能优化

    php - 我可以从 MySQL 数据库中进行选择,但是当我运行此插入时没有任何反应(仅插入到 1 个表中)

    c# - List<List<string>> 上的 Linq 计数组

    c# - 安装 Windows 10 Fall Creators Update 后无法运行任何 ASP.net MVC 应用程序

    asp.net GridView分页器消失了!

    c# - 如何从 C# 中的中继器中查找 td?