Ну, почему бы тебе просто не спросить? :)
Позвольте мне попытаться понять ваше требование. Мне кажется, что вы смотрите на поток, представляющий собой линейный список (а не дерево) сообщений между двумя людьми. Я думаю, что вы можете позволить больше людей, чем просто два. Это было бы похоже на Facebook, поскольку кто-то публикует сообщение, и тогда любое количество людей может прочитать его, а затем начать добавлять комментарии. Когда вы добавляете комментарий, он попадает в цепочку, и вы начинаете получать обновления статуса и электронные письма, рассказывающие об активности в цепочке и так далее. Если предположить, что это то, что вам нужно, то схема, которую я предложил Big Mike , не совсем то, что вы ищете.
Вместо этого рассмотрим следующее:
Идея заключается в том, что каждый раз, когда пользователь запускает новую ветку / сообщение, он начинается с новой записи в таблице THREAD. Затем пользователь добавляется как THREAD_PARTICIPANT, а содержимое сообщения добавляется в MESSAGE, который указывает на содержащую THREAD. ФК от СООБЩЕНИЯ до ПОЛЬЗОВАТЕЛЯ указывает автора сообщения.
Когда пользователь читает сообщение, он получает запись в таблице MESSAGE_READ_STATE, указывающую, что он пометил сообщение как прочитанное, явно или неявно, в зависимости от того, как идут ваши требования.
Когда кто-то комментирует начальное сообщение в цепочке, второе СООБЩЕНИЕ добавляется с FK обратно в исходную THREAD, и автор ответа (пользователь) добавляется в таблицу THREAD_PARTICIPANT. И так происходит, когда сообщения добавляются в ветку одним, двумя или более участниками.
Чтобы получить самое последнее сообщение в любой цепочке, просто возьмите верхнюю 1 из отсортированного СООБЩЕНИЯ по убыванию в дату создания (или идентификационный ключ), где сообщение FK соответствует интересующей нити.
Чтобы получить самую последнюю обновленную ветку для пользователя, получите THREAD, относящуюся к первой 1, из отсортированного по убыванию сообщения на дату создания, когда сообщение находится в потоке, в котором пользователь является THREAD_PARTICIPANT.
Боюсь, я никогда не смогу заявить об этом в LINQ, не разбив LinqPad. Если у вас возникли проблемы с обнаружением моего отклонения от вышесказанного, я мог бы уточнить ответ с помощью определений таблиц и некоторого SQL. Просто спросите в комментариях.
РЕДАКТИРОВАТЬ: Разъяснение требований и реализации
Разъяснение требований: Изначально я думал о публично опубликованных сообщениях с возможностью комментирования, тогда как Шейн больше интересуется функцией прямых сообщений. В этом случае первоначальный получатель должен быть включен в таблицу THREAD_PARTICIPANT с самого начала.
Для ясности, давайте поместим несколько строк в таблицы. Вот сценарий, (в честь Дня Канады): Пользователь 1 DM Пользователь 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
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;