[英]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.