Проблема запроса LINQ to SQL (невозможно получить правильное значение) - PullRequest
1 голос
/ 01 августа 2011

Я пытаюсь создать почтовую систему (что-то похожее на gmail), но она будет служить системой личных сообщений.К сожалению (для меня), я застрял при написании запроса, в котором имя получателя сообщения будет отображаться в виде списка.

Вот схема базы данных для почтовой системы:

enter image description here

Я считаю, что схема в значительной степени ясна, но позвольте мне кратко объяснить каждую таблицу.В таблице MailState содержатся данные о расположении почты (Входящие, Отправленные, Корзина) каждой почты какого-либо пользователя.MailStatus имеет только два состояния: «Чтение» или «Новое».Очевидно, что имеет почтовый стол.

То, что я пытался последние пару часов, - отображать сообщения в «Отправленном» почтовом ящике для конкретного пользователя, и я почти сделал это.Проблема в том, что я не могу заставить мой запрос отображать правильное имя User.DisplayName, когда я проверяю, чей это почтовый ящик (определяется по идентификатору вошедшего в систему пользователя).

Вот код, которым я былиспользуя:

var _messages = from m in db.MailState
                        select m;

        if (mailboxType == "Inbox")
        {
           var mailbox = from m in _messages
                         where m.idUser == idUser
                         where m.Mail.idSender != idUser
                         where m.MailLocation.Name == mailboxType
                         select new { m.idMail, m.Mail.User.DisplayName, m.Mail.DateSent, m.Mail.Subject };

           lvMailbox.DataSource = mailbox;
        }
        else if (mailboxType == "Sent")
        {
            var mailbox = from m in db.MailState
                          where m.MailLocation.Name == mailboxType  
                          select new { m.Mail.idSender, m.idMail, m.Mail.DateSent, m.Mail.Subject, m.User.DisplayName };

            //mailbox = mailbox.Where(m => m.idSender == idUser);

            lvMailbox.DataSource = mailbox;
        }
        else
        {
            //NOTHING YET
        }          

        lvMailbox.DataBind();

Входящие работают правильно, но почтовый ящик «Отправленные» отображает имя зарегистрированного пользователя вместо имени получателя.Больше всего меня беспокоит то, что он отображает все правильно, если мой запрос не содержит условия where для вошедшего в систему пользователя.Вот почему мне нужна помощь.

PS Любые другие предложения (касающиеся кода, базы данных и т. Д.) Приветствуются!

Ответы [ 2 ]

2 голосов
/ 01 августа 2011

В ситуациях, когда существует два пути к таблице «Пользователь», запросы могут быть очень запутанными и приводить к результатам, аналогичным полученным для:

«Отправленный» почтовый ящик отображает имявошел в систему вместо отображения имени получателя.

Одна из вещей, которые я пытаюсь сделать перед выполнением нескольких запросов, - это попытка сгладить исходные данные запроса, чтобы сделать мои запросы более лаконичными.Примерно так:

var messages =
    from ms in db.MailState
    select new
    {
        idMail = ms.idMail,
        Subject = ms.Mail.Subject,
        DateSent = ms.Mail.DateSent,
        Location = ms.MailLocation.Name,
        Sender_idUser = ms.Mail.idSender,
        Sender_DisplayName = ms.Mail.User.DisplayName,
        Recipient_idUser = ms.idUser,
        Recipient_DisplayName = ms.User.DisplayName,
    };

Теперь, учитывая это, ваши существующие запросы будут выглядеть так:

/* Inbox */
var mailbox =
    from m in messages
    where m.Recipient_idUser == idUser
    where m.Sender_idUser != idUser
    where m.Location == mailboxType
    select new
    {
        m.idMail,
        m.Sender_DisplayName,
        m.DateSent,
        m.Subject
    };

/* Sent */
var mailbox =
    from m in messages
    where m.Location == mailboxType  
    select new
    {
        m.Sender_idUser,
        m.idMail,
        m.DateSent,
        m.Subject,
        m.Recipient_DisplayName
    };

Это должно быть немного проще для чтения и рассуждений.

Итак, отсюда я попытался представить записи, необходимые для представления отправки и получения электронной почты.

Допустим, у нас есть три пользователя: Анна, Билл и Бен.Если Энн отправит электронное письмо Биллу и Бену, мой messages запрос, приведенный выше, должен будет вернуть три записи - одну для «Отправленных» в почтовом ящике Анны и одну для «Входящей почты» Билла и Бена.

Field                 | Anne         | Bill       | Ben        |
----------------------+--------------+------------+------------+
idMail                | 1            | 1          | 1          |
Subject               | "Hi"         | "Hi"       | "Hi"       |
DateSent              | 2011/08/01   | 2011/08/01 | 2011/08/01 |
Location              | "Sent Items" | "Inbox"    | "Inbox"    |
Sender_idUser         | 1            | 1          | 1          |
Sender_DisplayName    | "Anne"       | "Anne"     | "Anne"     |
Recipient_idUser      | 1            | 2          | 3          |
Recipient_DisplayName | "Anne"       | "Bill"     | "Ben"      |

Это говорит мне о том, что данные, доступные из текущей структуры базы данных, не содержат информации, необходимой для определения того, кто является получателями для элемента в пользовательской папке «Отправленные».Фактически, это выдвигает на первый план проблему именования с полями "Recipient_ *".

Вот лучший запрос messages, чтобы начать запросы:

var messages =
    from m in db.Mail
    select new
    {
        idMail = m.idMail,
        Subject = m.Subject,
        DateSent = m.DateSent,
        Sender = new
        {
            idUser = m.idSender,
            DisplayName = m.User.DisplayName,
        },
        Locations =
            from ms in db.MailState
            where ms.idMail == m.idMail
            select new
            {
                Location = ms.MailLocation.Name,
                idUser = ms.idUser,
                DisplayName = ms.User.DisplayName,
            },
        Recipients =
            from ms in db.MailState
            where ms.idMail == m.idMail
            where ms.idUser != m.idSender
            select new
            {
                idUser = ms.idUser,
                DisplayName = ms.User.DisplayName,
            },
    };

Использование этого в качестве базового запросаВаши существующие запросы теперь могут выглядеть следующим образом:

/* Inbox */
var mailbox =
    from m in messages
    from r in m.Recipients
    where r.idUser == idUser
    select new
    {
        m.idMail,
        r.DisplayName,
        m.DateSent,
        m.Subject
    };

/* Sent */
var mailbox =
    from m in messages
    where m.Sender.idUser == idUser 
    select new
    {
        m.Sender.idUser,
        m.idMail,
        m.DateSent,
        m.Subject,
        Recipients =
            from r in m.Recipients
            select r.DisplayName,
    };

Эти запросы немного проще и должны быть очень легко обосновать их правильность или нет.

Нет необходимостиФильтруйте поле MailLocation либо, поскольку эта информация теперь собирается в самом запросе.

Единственное, что вам нужно сделать, это сгладить поле Recipients в одну строку для привязки данных.поскольку это набор отображаемых имен получателей, а не просто одна строка.

Надеюсь, это поможет.

1 голос
/ 01 августа 2011

Вот один из подходов, если вы можете изменить схему базы данных.

Добавьте новое поле в таблицу Mail, idRecipient, которое идентифицирует получателя сообщения.

(ВашТаблица MailState представляет данные для определенного почтового сообщения для определенного пользователя. Получатель является свойством сообщения (Mail), но хранится как свойство почты состояние . Если получатель может удалить сообщениеэта часть информации будет полностью удалена из вашей схемы.)

Как только вы заполните это поле, запрос станет намного проще.

var mailbox = from m in db.MailState
  where m.MailLocation.Name == mailboxType 
  where m.idUser == idUser
  select new { m.Mail.idRecipient,
               m.idMail,
               m.Mail.DateSent,
               m.Mail.Subject,
               m.User.DisplayName /*or recipient display name*/ };

Будет ли такой подход работатьдля вас?

(Изменить в ответ на комментарий)

Учитывая новую информацию о том, что между отправителем и получателем существует связь «многие-к-одному», в одну сторонуПодойти к этому можно с помощью подзапроса.

var mailbox = from m in db.MailState
  where m.MailLocation.Name == mailboxType 
  where m.idUser == idUser
  select new { 
              Recipients = from z in db.MailState
                   where z.idMail == m.idMail // outer join on message ID
                   where z.idLocation.Id != mailboxType // exclude sender
                   select z.User,
               m.idMail,
               m.Mail.DateSent,
               m.Mail.Subject,
               m.User.DisplayName
   };

Тогда mailbox.Recipients - это IEnumerable<User> (в зависимости от вашей модели), содержащий всех получателей сообщения.

(Примечание:по вашему требованию для хранения получателей в MailState необходимо, чтобы записи никогда не удалялись из MailState, поскольку это единственный репозиторий для информации о получателях.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...