简体   繁体   English

如何使用实体框架和MySQL(包括相关实体)获取每个组的最新记录

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

I am using Entity Framework with a MySQL Database and DbContext. 我正在使用带有MySQL数据库和DbContext的实体框架。 I have an entity "Message" that has a related entity "Sender". 我有一个具有相关实体“发件人”的实体“消息”。 (The "Message" also has a related entity "Receiver"). (“消息”还具有相关的实体“接收者”)。 I am trying to write a query that will return only the "latest" message for each receiver. 我正在尝试编写一个查询,该查询将为每个接收者仅返回“最新”消息。 But when I do this, I also want to load the associated "Sender" so that I can get access to one of the Sender's properties (e-mail field) which I need to include in my Data Transfer Object I am returning. 但是,当我这样做时,我还想加载关联的“发件人”,以便可以访问要包含在我要返回的数据传输对象中的发件人属性之一(电子邮件字段)。 "MessageDTO" is the Data Transfer Object I am returning that includes the id of the message, the content of the message and the sender's email. “ MessageDTO”是我要返回的数据传输对象,其中包括消息的ID,消息的内容和发送者的电子邮件。

If I exclude the sender's email from the DTO, then the following query returns exactly what I need (namely, the latest message for each receiver): 如果我从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});

However, the above statement does not load the Sender that is associated with the Message so when I re-include the sender's email in the DTO I get a NullReferenceException as shown below: 但是,上面的语句不会加载与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 throws a NullReferenceException because sender is null. refGroup.FirstOrDefault()。sender.email会引发NullReferenceException,因为发件人为null。

How can I load the Sender in the query so that I can include the Sender's email in my DTO? 如何在查询中加载发件人,以便可以在DTO中包含发件人的电子邮件?

EDIT: 编辑:

As requested, I include the SQL that gets generated by Gert Arnold's suggested method: 根据要求,我包括由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`}

You don't need the SqlQuery construct to do the ordering before the grouping: 在分组之前,您不需要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
                           };

This does the same, but it translates the whole statement into SQL, which has two advantages 这样做是一样的,但是它将整个语句转换为SQL,这有两个优点

  • sender is not lazy loaded for each message 每个邮件的sender不是延迟加载的
  • sender.email does not crash when sender is null, because in SQL there is no null object reference. sender为null时, sender.email不会崩溃,因为在SQL中没有null对象引用。 The whole expression ( sender.email ) just returns null. 整个表达式( sender.email )仅返回null。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM