我正在尝试做一个相对基本的SQL语句来连接和分组一些表并用汇总函数进行汇总。我会用SQL编写它:
select
p.LocationID,
NumReadings = count(*),
MinDate = min(t.[DateTime]),
MaxDate = max(t.[DateTime])
from Station p inner join Data pd on p.LocationID = pd.ReadingLocationID
inner join ApplicationDateTime t on t.ApplicationDateTimeID = pd.DateTimeID
group by p.LocationID
当我在EF4中使用下面的Linq语句时,它会创建一些可怕的SQL(参见最底部)。有更好的方法吗?明确地进行连接而不是使用EF导航属性会使情况更糟。
我不关心美学,但是查看查询执行,执行格式错误的SQL需要3-4倍的时间。
from s in Station
select new DataSummary
{
ReadingLocationID = s.ReadingLocationID,
StationIdentifier = s.StationIdentifier,
NumReadings = s.Data.Count(),
MinDateLoaded = s.Data.Min(d => d.ApplicationDateTime.DateTime),
MaxDateLoaded = s.Data.Max(d => d.ApplicationDateTime.DateTime)
};
这是SQL(注意:这里有一些额外的复杂性,比如表示为另一个连接的继承关系,但这只会导致另一个嵌套级别。)
SELECT
[Project3].[LocationTypeID] AS [LocationTypeID],
[Project3].[ReadingLocationID] AS [ReadingLocationID],
[Project3].[LocationIdentifier] AS [LocationIdentifier],
[Project3].[C1] AS [C1],
CAST( [Project3].[C2] AS datetime2) AS [C2],
CAST( [Project3].[C3] AS datetime2) AS [C3]
FROM ( SELECT
[Project2].[ReadingLocationID] AS [ReadingLocationID],
[Project2].[LocationTypeID] AS [LocationTypeID],
[Project2].[LocationIdentifier] AS [LocationIdentifier],
[Project2].[C1] AS [C1],
[Project2].[C2] AS [C2],
(SELECT
MAX([Extent7].[DateTime]) AS [A1]
FROM [dbo].[Data] AS [Extent6]
INNER JOIN [dbo].[ApplicationDateTime] AS [Extent7] ON [Extent6].[DateTimeID] = [Extent7].[ApplicationDateTimeID]
WHERE [Project2].[ReadingLocationID] = [Extent6].[ReadingLocationID]) AS [C3]
FROM ( SELECT
[Project1].[ReadingLocationID] AS [ReadingLocationID],
[Project1].[LocationTypeID] AS [LocationTypeID],
[Project1].[LocationIdentifier] AS [LocationIdentifier],
[Project1].[C1] AS [C1],
(SELECT
MIN([Extent5].[DateTime]) AS [A1]
FROM [dbo].[Data] AS [Extent4]
INNER JOIN [dbo].[ApplicationDateTime] AS [Extent5] ON [Extent4].[DateTimeID] = [Extent5].[ApplicationDateTimeID]
WHERE [Project1].[ReadingLocationID] = [Extent4].[ReadingLocationID]) AS [C2]
FROM ( SELECT
[Extent1].[ReadingLocationID] AS [ReadingLocationID],
[Extent1].[LocationTypeID] AS [LocationTypeID],
[Extent1].[LocationIdentifier] AS [LocationIdentifier],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Data] AS [Extent3]
WHERE [Extent1].[ReadingLocationID] = [Extent3].[ReadingLocationID]) AS [C1]
FROM [dbo].[ReadingLocation] AS [Extent1]
INNER JOIN [dbo].[Station] AS [Extent2] ON [Extent1].[ReadingLocationID] = [Extent2].[LocationID]
WHERE ([Extent1].[LocationTypeID] = CAST( '1' AS int)) AND ([Extent2].[LineID] = 'ACBB3FDF-116C-4E8E-AA80-B925E4922AC8')
) AS [Project1]
) AS [Project2]
)
帮助!感谢。
答案 0 :(得分:1)
使用不同的ORM怎么样?具体而言,诸如PetaPoco或Massive之类的MicroOrm将允许您在SQL中编写查询并返回.NET对象。
两者都是Nuget包:PetaPoco,Massive因此您可以轻松安装它们。
如果您习惯于编写SQL并希望控制您的查询,那么它们可能是可行的候选者。
答案 1 :(得分:0)
LINQ可以做很多事,但绝对不是魔术。 尝试编写LINQ,就像编写SQL一样。定义你的联接。
这是你的LINQ语句应该是这样的:
Station
.Join(Data, s => new { s.LocationID }, d => new { LocationID = d.ReadingLocationID }, (s,d) => new { s.ID, s.LocationID, d.DateTimeID })
.Join(ApplicationDateTime, j1 => new { j1.DateTimeID }, t => new { DateTimeID = t.ApplicationDateTimeID }, (j1,t) => { j.ID, j.LocationID, t.DateTime })
.Group(j2 => new { j2.ID, j2.LocationID })
.Select(g => new DataSummary
{
StationIdentifier = g.Key.ID,
ReadingLocationID = g.Key.LocationID,
NumReadings = g.Count(),
MinDateLoaded = g.Min(j2 => j2.DateTime),
MaxDateLoaded = g.Max(j2 => j2.DateTime)
});
注意:上面提供的代码未经过测试!
请记住,在LINQ中创建连接时,在连接中使用的匿名对象的属性应具有相同的名称和类型。这花了我一些时间让我的第一次加入工作。 示例:假设Data表上的DateTimeID列可以为NULL,ApplicationDateTime上的ApplicationDateTimeID列不能为NULL。然后,您应该将该连接更改为:
.Join(ApplicationDateTime, j1 => new { j1.DateTimeID }, t => new { DateTimeID = (int?)t.ApplicationDateTimeID }, (j1,t) => { j.ID, j.LocationID, t.DateTime })