【发布时间】:2018-07-31 11:43:47
【问题描述】:
我正在尝试编写一个 LINQ-to-entities 查询,该查询将采用我的主要对象的 ICollection 导航属性并将一些元数据附加到它们中的每一个,这是通过将它们中的每一个连接到另一个数据库表来确定的,并且使用聚合函数。所以主要对象是这样的:
public class Plan
{
...
public virtual ICollection<Room> Rooms { get; set; }
}
我的查询是这样的:
var roomData = (
from rm in plan.Rooms
join conf in context.Conferences on rm.Id equals conf.RoomId into cjConf
select new {
RoomId = rm.Id,
LastUsedDate = cjConf.Count() == 0 ? (DateTime?)null : cjConf.Max(conf => conf.EndTime)
}
).ToList();
我想要的是它生成一些使用聚合函数MAX 来计算LastUsedDate 的高效SQL,如下所示:
SELECT
rm.Id, MAX(conf.EndTime) AS LastUsedDate
FROM
Room rm
LEFT OUTER JOIN
Conference conf ON rm.Id = conf.RoomId
WHERE
rm.Id IN ('a967c9ce-5608-40d0-a586-e3297135d847', '2dd6a82d-3e76-4441-9a40-133663343d2b', 'bb302bdb-6db6-4470-a24c-f1546d3e6191')
GROUP BY
rm.id
但是当我分析 SQL Server 时,它会显示来自 EF 的这个查询:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[RoomId] AS [RoomId],
[Extent1].[ProviderId] AS [ProviderId],
[Extent1].[StartTime] AS [StartTime],
[Extent1].[EndTime] AS [EndTime],
[Extent1].[Duration] AS [Duration],
[Extent1].[ParticipantCount] AS [ParticipantCount],
[Extent1].[Name] AS [Name],
[Extent1].[ServiceType] AS [ServiceType],
[Extent1].[Tag] AS [Tag],
[Extent1].[InstantMessageCount] AS [InstantMessageCount]
FROM [dbo].[Conference] AS [Extent1]
所以它是从 Conference 中选择 everything 并在内存中进行 Max() 计算,这是非常低效的。如何让 EF 使用聚合函数生成正确的 SQL 查询?
【问题讨论】:
-
您的查询源自物化对象 (
plan),因此整个查询将在 LINQ to Objects 上下文中执行。这意味着context.Conferences被视为IEnumerable,从而将整个表加载到内存中。例如,将查询根更改为context.Rooms。 -
@mjwills EF 6.2.0.
-
@IvanStoev 但是如果我使用
context.Rooms,我该如何过滤到与Plan关联的房间? -
如果您愿意,您可以从
context.Plans开始,或者从context.Rooms开始并使用.Where(room => room.PlanId == plan.Id)之类的名称。重点是从EFIQueryable开始。 -
那你为什么不用
where rm.PlanId == plan.Id作为过滤器呢?plan.Rooms是否被额外过滤?但你总是可以做var roomIds = plan.Rooms.Select(rm => rn.Id); var query = from rm in context.Rooms where roomsIds.Contains(rm.Id) …
标签: c# sql-server entity-framework linq linq-to-entities