簡體   English   中英

如何使用實體框架和MySQL(包括相關實體)獲取每個組的最新記錄

[英]How to get latest record for each group using Entity Framework and MySQL including related entity

我正在使用帶有MySQL數據庫和DbContext的實體框架。 我有一個具有相關實體“發件人”的實體“消息”。 (“消息”還具有相關的實體“接收者”)。 我正在嘗試編寫一個查詢,該查詢將為每個接收者僅返回“最新”消息。 但是,當我這樣做時,我還想加載關聯的“發件人”,以便可以訪問要包含在我要返回的數據傳輸對象中的發件人屬性之一(電子郵件字段)。 “ MessageDTO”是我要返回的數據傳輸對象,其中包括消息的ID,消息的內容和發送者的電子郵件。

如果我從DTO中排除了發件人的電子郵件,則以下查詢將准確返回我需要的內容(即每個收件人的最新消息):

var refGroupQuery = (from m in dbContext.Messages.SqlQuery("select * from messages order by created_at desc")
     group m by m.receiver_id into refGroup
     select new MessageDTO { id = refGroup.FirstOrDefault().id, content = refGroup.FirstOrDefault().content});

但是,上面的語句不會加載與Message相關的發件人,因此當我在DTO中重新包含發件人的電子郵件時,會收到NullReferenceException,如下所示:

var refGroupQuery = (from m in dbContext.Messages.SqlQuery("select * from messages order by created_at desc")
     group m by m.receiver_id into refGroup
     select new MessageDTO { id = refGroup.FirstOrDefault().id, content = refGroup.FirstOrDefault().content, sender_email = refGroup.FirstOrDefault().sender.email});

refGroup.FirstOrDefault()。sender.email會引發NullReferenceException,因為發件人為null。

如何在查詢中加載發件人,以便可以在DTO中包含發件人的電子郵件?

編輯:

根據要求,我包括由Gert Arnold的建議方法生成的SQL:

{SELECT
1 AS `C1`, 
`Apply1`.`id`, 
`Apply1`.`sender_id`, 
`Apply1`.`RECEIVER_ID1` AS `receiver_id`, 
`Apply1`.`created_at`, 
`Apply1`.`read_status`, 
`Extent3`.`email`
FROM (SELECT
`Distinct1`.`receiver_id`, 
(SELECT
`Project2`.`id`
FROM (SELECT
`Extent2`.`id`, 
`Extent2`.`sender_id`, 
`Extent2`.`receiver_id`, 
`Extent2`.`created_at`, 
`Extent2`.`read_status`
FROM `messages` AS `Extent2`
 WHERE (`Extent1`.`receiver_id` = `Extent2`.`receiver_id`) OR ((`Extent1`.`receiver_id` IS  NULL) AND (`Extent2`.`receiver_id` IS  NULL))) AS `Project2` LIMIT 1) AS `id`, 
(SELECT
`Project2`.`sender_id`
FROM (SELECT
`Extent2`.`id`, 
`Extent2`.`sender_id`, 
`Extent2`.`receiver_id`, 
`Extent2`.`content`, 
`Extent2`.`created_at`, 
`Extent2`.`read_status`
FROM `messages` AS `Extent2`
 WHERE (`Extent1`.`receiver_id` = `Extent2`.`receiver_id`) OR ((`Extent1`.`receiver_id` IS  NULL) AND (`Extent2`.`receiver_id` IS  NULL))) AS `Project2` LIMIT 1) AS `sender_id`, 
(SELECT
`Project2`.`receiver_id`
FROM (SELECT
`Extent2`.`id`, 
`Extent2`.`sender_id`, 
`Extent2`.`receiver_id`, 
`Extent2`.`content`, 
`Extent2`.`created_at`,
`Extent2`.`read_status`
FROM `messages` AS `Extent2`
 WHERE (`Extent1`.`receiver_id` = `Extent2`.`receiver_id`) OR ((`Extent1`.`receiver_id` IS  NULL) AND (`Extent2`.`receiver_id` IS  NULL))) AS `Project2` LIMIT 1) AS `RECEIVER_ID1`, 
(SELECT
`Project2`.`receivable_type`
FROM (SELECT
`Extent2`.`id`, 
`Extent2`.`sender_id`, 
`Extent2`.`receiver_id`, 
`Extent2`.`content`, 
`Extent2`.`created_at`,  
`Extent2`.`read_status`
 WHERE (`Extent1`.`receiver_id` = `Extent2`.`receiver_id`) OR ((`Extent1`.`receiver_id` IS  NULL) AND (`Extent2`.`receiver_id` IS  NULL))) AS `Project2` LIMIT 1) AS `content`, 
(SELECT
`Project2`.`created_at`
FROM (SELECT
`Extent2`.`id`, 
`Extent2`.`sender_id`, 
`Extent2`.`receiver_id`,  
`Extent2`.`content`, 
`Extent2`.`created_at`, 
`Extent2`.`read_status`
FROM `messages` AS `Extent2`
 WHERE (`Extent1`.`receiver_id` = `Extent2`.`receiver_id`) OR ((`Extent1`.`receiver_id` IS  NULL) AND (`Extent2`.`receiver_id` IS  NULL))) AS `Project2` LIMIT 1) AS `created_at`, 
(SELECT
`Project2`.`updated_at`
FROM (SELECT
`Extent2`.`id`, 
`Extent2`.`sender_id`, 
`Extent2`.`receiver_id`, 
`Extent2`.`content`, 
`Extent2`.`created_at`, 
`Extent2`.`read_status`
FROM `messages` AS `Extent2`
 WHERE (`Extent1`.`receiver_id` = `Extent2`.`receiver_id`) OR ((`Extent1`.`receiver_id` IS  NULL) AND (`Extent2`.`receiver_id` IS  NULL))) AS `Project2` LIMIT 1) AS `read_status`
FROM (SELECT DISTINCT 
`Extent1`.`receiver_id`
FROM `messages` AS `Extent1`) AS `Distinct1`) AS `Apply1` LEFT OUTER JOIN `users` AS `Extent3` ON `Apply1`.`sender_id` = `Extent3`.`id`}

在分組之前,您不需要SqlQuery構造來進行排序:

var refGroupQuery = from m in dbContext.Messages
     group m by m.receiver_id into refGroup
     let firstItem = refGroup.OrderByDescending(x => x.created_at)
                             .FirstOrDefault()
     select new MessageDTO { 
                              id = firstItem.id, 
                              content = firstItem.content,
                              sender_email = firstItem.sender.email
                           };

這樣做是一樣的,但是它將整個語句轉換為SQL,這有兩個優點

  • 每個郵件的sender不是延遲加載的
  • sender為null時, sender.email不會崩潰,因為在SQL中沒有null對象引用。 整個表達式( sender.email )僅返回null。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM