C# 如何使用实体框架和MySQL(包括相关实体)获取每个组的最新记录
我将实体框架与MySQL数据库和DbContext一起使用。我有一个实体“Message”,它有一个相关实体“Sender”。(该“消息”还具有相关实体“接收者”)。我试图编写一个查询,只返回每个接收者的“最新”消息。但在执行此操作时,我还希望加载关联的“发件人”,以便能够访问发件人的一个属性(电子邮件字段),该属性需要包含在返回的数据传输对象中。“MessageDTO”是我返回的数据传输对象,包括消息的id、消息的内容和发件人的电子邮件 如果我将发件人的电子邮件从DTO中排除,则以下查询将准确返回我需要的内容(即每个收件人的最新消息): 但是,上面的语句不会加载与邮件关联的发件人,因此,当我将发件人的电子邮件重新包含在数据中时,我会得到一个NullReferenceException,如下所示:C# 如何使用实体框架和MySQL(包括相关实体)获取每个组的最新记录,c#,mysql,linq,entity-framework,C#,Mysql,Linq,Entity Framework,我将实体框架与MySQL数据库和DbContext一起使用。我有一个实体“Message”,它有一个相关实体“Sender”。(该“消息”还具有相关实体“接收者”)。我试图编写一个查询,只返回每个接收者的“最新”消息。但在执行此操作时,我还希望加载关联的“发件人”,以便能够访问发件人的一个属性(电子邮件字段),该属性需要包含在返回的数据传输对象中。“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, 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.email
为null时不会崩溃,因为在SQL中没有null对象引用。整个表达式(sender
)只返回nullsender.email
SqlQuery
?如果没有它,整个查询将被翻译成SQL,发送者也将加入其中。使用SqlQuery是我能够在“分组依据”之前执行“order by”的唯一方法。如果我用“order by”指令替换SqlQuery,查询将不再返回每个组的最新记录,而是返回每个组的一些记录。我读到“添加ORDER by子句不会影响从每个组中选择值。结果集的排序发生在选择值之后,ORDER by不会影响服务器选择的值”这在“where子句”中给出了一个错误“未知列'Extent1.receiver_id'实际上,我使用的正是你提供的方法。在我的方法中,我所做的额外工作就是将refGroupQuery返回给调用函数。我想知道这是MySQL还是MySQL适配器中的错误。我发现,我确实在使用6.6.5版本的适配器。所以看起来我需要先升级到一个新版本…我是说整个SQL查询:)恐怕很可能会出现错误,但这可能是一个映射问题。消息
和接收者
之间的映射是什么样的?您是否明确命名了receiver\u id
列,还是依赖EF的默认命名约定?(我假设您首先在这里使用代码)。我已将生成的SQL查询添加到问题中。实际上,我采用了数据库优先的方法,因为我们有一个由RubyonRails提供服务的现有数据库,其中WebAPI功能正在转移到.NET。我不依赖EF的默认命名约定,因为它们在我们的情况下不起作用。“messages”表有一个“receiver_id”字段,它是“users”表中“id”的外键。因此,该消息将有一个接收器。肯定是一个错误Extent1
的作用域是底部的一个子查询,但在任何地方都可以引用。
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
};